Yeah, I'm just as lost. The only way to get the results you were getting is if theta was an integer multiple of pi/2, including 0. Maybe set theta to 5.0 instead of just 5, although I'd be kinda exasperated if that were the answer.

Actually, maybe try logging for different values of theta (I'd probably try multiples of pi/4, or some such). If they all turn out the same, something is setting theta to 0 for calculations, but somehow not for logging. If that's the case, then you can try to find something that would change theta or something that would create scope conflicts or something like that. The only other outcome that makes sense is that this would fix it, and that only makes sense if BGT does very strange things with typecasting under the hood.

Interesting. So here's what I did. I created two new variables:

double T1 = cosine(theta);

double T2 = sine(theta);

Then, I told the ball to move, with a theta of 4.3. Logs showed that T1, or cosine(theta), was equal to 1. Sine(theta), was shown as 0. So next, instead of passing theta to move, I bypassed it, and simply changed theta manually to 4.3:

double theta = 4.3;

And now, the log has totally different values, and different cords: T1 is -0.400799172079975, and T2 is -0.916165936749455.

Ball is now at -0.014063128270208, -0.032146170735359, 499.803802490234.

So that means somehow theta isn't getting updated correctly. In other words, when I use:

void move(double theta)

And I say something like move(4.3), it's not actually updating it, even though the log says it is, or somehow it's not staying at that value. Is that correct?

That is exactly what it sounds like. I'd need to check how theta is used/declared elsewhere to figure out the best way to fix it, but this suggests it's some kind of scope conflict, where multiple thetas are being created and the right one is not being used.

Theta is declared in math.bgt. Code relevant to theta:

double CT = 1.2;

double DT;

double T1 = cosine(theta);

double T2 = sine(theta);

double theta; (this is the theta I manually changed)

double deg;

...

double RTD(double theta)

{

return deg = theta*180/pi;

}

double DTR(double deg)

{

return theta = deg*pi/180;

}

That is the only place where I declare theta. The only other place I pass it is move. I do that so that theta can change based on shot chosen.

void move(double theta)

And then, i.e., pseudocode:

if shot 1, then move(1)

If shot 2, then move(2.5)

etc. There are no other uses of theta.

### 80 2017-09-14 17:06:14 (edited by JLove 2017-09-14 17:17:35)

Ok, I think I discovered the issue.

I wanted to track when theta was changing value, so I did the following:

I added the following lines to main():

test.write("test.log", true);

test.add_entry("Theta in main is " + theta + ".");

In ball:

test.write("test.log", true);

test.add_entry("Theta in move is " + theta + ", T1 is " + T1 + ", and T2 is " + T2 + ".");

And in math, I had to create a function, since it seems that for some reason you can only write to a log file within a function:

void debug()

{

test.write("test.log", true);

test.add_entry("Theta in math is " + theta + ".");

}

This is what the log shows:

Theta in main is 0.

Theta in move is 4.5, T1 is 1, and T2 is 0.

Absolutely nothing, not even 0, in math. Math is not listed at all in the log, and it should be. What this looks like to me is that the original theta, the one in math, which is the only one I declared, isn't changing at all. Evidence of this is in the values of 1 and 0 respectively for T1 and T2. Keep in mind that if theta were truly 4.5, then T1 and T2 would be much different, since T1 = cosine(theta), and T2 = sine(theta). If I were to go into math and change double theta; to double theta = 4.5, then theta is now changed in main, in move it remains 4.5, and now T1 and T2 are:

Theta in main is 4.5.

Theta in move is 4.5, T1 is -0.21079579943078, and T2 is -0.977530117665097.

What that seems to mean is that somehow, a new theta is being declared in void move(double theta)

or the value for theta isn't updating correctly. The thing is, I never declare another theta other than in math: double theta;

In move, I do not declare theta:

void move(double theta)

{

B.moving = true;

test.write("test.log", true);

test.add_entry("Theta in move is " + theta + ", T1 is " + T1 + ", and T2 is " + T2 + ".");

B.pos += vel*DT;

test.add_entry("Ball is now at " + B.pos.x + ", " + B.pos.y + ", " + B.pos.z + ".");

env.update_sound_2d(B.slot, B.pos.x, B.pos.y);

... //more code related to frames and such.

It almost looks like the line void move(double theta) is somehow creating a separate variable named theta. I've never had that happen before. I thought that it was legal to say: void function(data type variable), and it would simply pass the original declared variable value, not create a new one. Which means that when I say:

move(2.6)

the original theta that I declared in math should become 2.6. This is how it has always worked for me in the past. If I passed a variable, i.e., void move(int direction), or void shot(int ShotType), it always updated correctly. This should be no different. And besides, now that I think about it, theoretically, if it is creating another instance of theta, then wouldn't I get a compiler error based on name conflict? I think it's something like: "'theta' is already declared."

This issue makes no damn sense to me.

I think there's a chapter somewhere in the language tutorial on scope, but basically, function parameters are creating local variables (which is why we have to pass around handles when dealing with objects). The name conflicts happen only in the same scope, so you can technically have four separate thetas, in global (that'd be the one in math.bgt), local to main, local to ball::move, and as a property/instance variable/member variable (the terminology on this one is either woefully inconsistent, or more complex than I'm aware) for the ball class.

So, in the move function, you could access the local theta (theta), the ball's theta (this.theta), or the global theta (::theta), but not a hypothetical theta declared in main, even though main is technically still on the stack.

A quick fix might be to add the following to the move function, near the top. It's not going to resolve the scope issues, but that could take some major reorganizing of your variables, so this is something of a [email protected]:

::theta = theta;

I don't remember if I've ever tried anything like that, but either it will work, or the compiler will have a very self-explanetory complaint.

Any way to use a handle to reference the correct theta? I tried something like:

void move([email protected] T)

but the compiler wasn't pleased. The only global variables I have for the purposes of this test are in the main test script, vectest.bgt:

#include "sound_pool.bgt"

#include "voice.bgt"

#include "math.bgt"

#include "ball.bgt"

#include "clock.bgt"

#include "player.bgt"

#include "logger.bgt"

#include "snapshot.bgt"

Voice speaker;

sound_pool env;

ball B;

player user;

player opponent;

logger test;

bool testing;

clock C(150);

void main()

{

show_game_window("");

init(); //This is simply to return DT correctly.

B.pos.z = 500; ..Giving the ball enough height for testing.

while(true)

{

move(2.5);

//Just different key checks for testing purposes, to make sure values are correct.

if(key_pressed(KEY_D))

speaker.speak(drag.x + ", " + drag.y + ", " + drag.z + ".");

if(key_pressed(KEY_P))

speaker.speak(B.pos.x + ", " + B.pos.y + ", " + B.pos.z + ".");

if(key_pressed(KEY_V))

speaker.speak(vel.x + ", " + vel.y + ", " + vel.z + ".");

if(key_pressed(KEY_F))

speaker.speak(C.frame);

}

}

void move(double theta)

{

B.moving = true;

test.write("test.log", true);

B.pos += vel*DT;

test.add_entry(C.frame);

if(B.pos.z <= 0)

{

env.destroy_all();

B.moving = false;

testing = false;

exit();

}

if(C.frame == 5)

{

B.slot = env.play_2d("sounds/ball.ogg", user.x, user.y, B.pos.x, B.pos.y, false);

C.frame = 0;

}

C.tick();

C.update();

env.update_sound_2d(B.slot, B.pos.x, B.pos.y);

}

As you can see, no theta. in ball.bgt:

class ball

{

float x, y, z;

vector pos(0, 0, 0);

int slot;

//These booleans will be adjusted given the new vector implementation, but for now, they can remain.

bool tossing = false;

bool moving = false;

bool rising = false;

bool choosing = false;

ball()

{

x = 0;

y = 0;

z = 0;

}

ball(float x, float y, float z, int slot)

{

this.x = x;

this.y = y;

this.z = z;

this.slot = slot;

}

Again, no declaration of theta.

In math.bgt:

double CT = 1.2;

double DT;

double theta;

double deg;

float M2 = 0.057;

float x, y, z;

float d;

float roh = 1.151;

float A = 0.0033;

float CD = 0.507;

float FL;

float DX = (CD*roh*A)*power((vel.x/2),2);

float DY = (CD*roh*A)*power((vel.y/2),2);

float DZ = (CD*roh*A)*power((vel.z/2),2);

const double pi = 3.14159265358979;

As you can see, this is the only theta. And since math.bgt is not a class, these variables should be treated as global, just as they are in the main vectest.bgt script. If I change theta in math.bgt, it does change in main. However, if I pass theta to ball, it does not change in main, which means the theta in math.bgt is not being updated correctly. I'm not sure how there is a scope issue, since any variable in math.bgt is global.

I *think* that you can use the &out; to make a C-style pointer out of a number, but that's almost certainly not what you want to do, here. You can't use handles on primatives, which numbers and bools are. I'm not sure about strings.

I think the main confusion here is over how variables are managed internally. I can try to explain how that should work in this case, but it might take a while.

The only other possibility that I can think of is that the global theta declaration in math.bgt only applies to math.bgt. In other words, it's global to any function within math.bgt, but when it's passed to another script, like vectest.bgt, it doesn't update correctly because it's outside of math.bgt. I'm not positive; it's just a thought.

I have a suspicion that if I made math a class and declared theta there it would work correctly. But I was hoping to avoid doing that. To me, it just makes sense for them to be global. Math is math, global across the board. Specific formulae related to physics are immutable. I shouldn't need a specialized class for this. The only two vectors that make any sense to me being in a class at all are the ones for position of the ball in the ball class, and the position of the player in the player class. Other than that, to me it makes the most logical sense for all other vectors related to physics to be global, and for all specific formulae to be global as well.

Interesting...I tried ::theta = theta; and the compiler was fine with that. It did change theta in math.bgt, but the values for T1, which is cosine(theta), and T2, which is sine(theta), are still 1 and 0 respectively, which is incorrect. Please see my above post re class, but I would really prefer not to do that.

### 86 2017-09-17 02:04:00 (edited by JLove 2017-09-17 02:07:31)

So until I figure out what the hell to do about getting theta to pass and change correctly, preferably without making math a class, I decided to test whether theta would control the direction correctly. Which brings me to the following question: What...the...fuck? Radian values should be immutable. In other words:

if 90 degrees = 1.5707963268 radians, and knowing that position = velocity*DT:

double theta = 1.5707963268;

vector vel((acc.x/M2)*cosine(theta), (acc.y/M2)*sine(theta), grav.z);

This should make the ball travel 90 degrees. That would mean that it would travel strictly on the x axis, and none on y, meaning that Y should remain 0. However, this is what the log shows the travel to be. I've only shown the first 5 entries, but you will see what I mean:

position of ball.x is -0.000000000019894, position of ball.y is 3.8982412815094.

position of ball.x is -0.000000000039591, position of ball.y is 7.75790357589722.

position of ball.x is -0.000000000059289, position of ball.y is 11.6175222396851.

position of ball.x is -0.000000000078986, position of ball.y is 15.4771375656128.

position of ball.x is -0.000000000098684, position of ball.y is 19.3368358612061.

I see two problems here. First of all, the ball is travelling along the Y axis instead of the X one, meaning that it's going straight ahead. Last time I checked, that's not 90 degrees. Second of all, the ball is moving very, very, very slowly along the X axis, but apparently in the wrong direction, as the numbers are negative, which would mean the ball is moving to the left. Again, not 90 degrees. And I know that my math is correct. I doubt very seriously that every website showing the value of 1.5707963268 radians is that mathematically fucked up. And I just verified it with a calculator. So, again, my question is, what...the...fuck?

### 87 2017-09-17 05:15:59 (edited by CAE_Jones 2017-09-17 05:20:30)

0 radians generally points along the positive x axis, so I would expect 90dg to move along the y axis.

As for x, notice the number of 0s. This is the limitation of floating point arithmetic, aka rounding error. Pi/2 is an irrational number with infinitely many digits. You can't represent all of those in 64 bits. You can't represent all of those in 9000 bits, because 9000 is less than infinity. So you inevitably have *some* minor discrepencies due to rounding. As a general rule, physics in the real world struggles beyond the 8th decimal place, unless you're dealing with quantum mechanics, for which PCs are woefully inadequate. So, if the drift due to rounding errors is small enough that it wouldn't be measurable by a human in any cases that are going to show up, it's generally safe to treat 0.00000001 as 0.

I mean, you have 10 zeros after the decimal point. If you're measuring in meters, that is enough accuracy that you'd need some very expensive equipment to detect the difference. It's still bigger than atoms, but I'm not sure that a paramecium would notice.

So I'm just trying to figure this out from the player point of view. If X is side to side movement, and y is front to back, and if 90 degrees makes the ball move along y, front to vack, then that would mean that the player actually starts out facing 90 degrees. Is that correct? Meaning that 180 degrees would go to the player's left, and 270 degrees would be behind the player. Is that right? I never knew that. thought that facing straight ahead would be 0, 90 to the right, 180 behind me, and 270 directly left.

Yeah. I think this is why Swamp tends to start players off facing east. If you put compass directions on the x/y axes, 0dg is east, 90dg is north, 180dg is west, and 270dg is south. ... unless you're using screen coordinates, in which case north and south would be reversed, but once you go to 3 dimensions, there's usually not much point in bothering with screen coordinates, since those are based on pixel arrays.

So how would I best handle this? How would I determine where the player starts out facing when the game starts? Is there a way to make it the way I originally thought it was, 90 degrees to the right, 180 behind, 270 left, and 0 straight ahead, or are the values of 0 being along y, etc. set in stone? I also need to know because it affects the sound pool and the way the ball sound travels as it's updated.

It sounds like you want -theta+90. You could either apply that to whatever takes theta, or you could just set 90 as the default and transform any messages.

To get 0=+y, 90=+x, ... let's call it the 12o'clock system, and the 0=+x, 90=+y version the right-handed system...

From right-handed to 12:00: theta12 = 90-theta_rh. From 12:00 to right-handed: theta_rh = 90-theta12. ... Use pi/2 if you want to do the same for radians.

As for which to apply where, that really depends on what you're aiming for. If you want to work with 12o'clock values, then put the conversion at the top of any function that uses theta for major calculations. The only question that follows is how you'd reference theta later, which brings us back to the previous issue.

### 92 2017-09-19 14:27:41 (edited by JLove 2017-09-19 14:32:53)

guess that I am going to have to get used to the adjustment of Y being travelled with 90 degrees, and the counter-clockwise system in and of itself because of the way sound pool updates. Shots that I would normally expect to go to the right go straight ahead, etc. So if I want to hit the ball directly in front of me to the other side of the court, I have to hit a 90-degree shot. I suspect that for a while that's going to feel totally weird. As for the other issue re theta declaration and passing, I still haven't figured out what to do with that one. It is going to annoy me if I have to make math a class. It's ridiculous and should be unnecessary, given that math is immutable...2+2 is always going to be 4. The thing is, I suspect that if I do that, it will probably work correctly, since I can specify to use that particular theta. I don't need 15 thetas. But surely there's got to be another way of doing it.

It seems like you wouldn't need a global theta, so much as the orientations of the players / the ball. In that case, you could have theta be a property of those objects, so the only time you'd need to pass theta around is if you're using global functions, or changing direction.

So I will also need two separate velocity vectors, one for the player, one for the ball. I don't think I'm going to worry with drag, friction, and all that shit related to the player, so I won't need duplicates of those.