2019-02-18 22:11:39 (edited by JLove 2019-02-18 23:16:53)

So, what in the world would drop me to 50 FPS when running at 60?  I mean, my code should not be taxing my PC at all.  I'm running latest version of windows.  I've got 16 GB ram with an I7 processor.  No graphics in this game at all.  Graphics tend to lag a machine, yes, but there's no graphical issue here.  So what the hell is bogging down my machine to the level that it drops framerate from 60 to 50?  I would think whatever is doing that would have to be massively resource-intensive.  Nothing running on my PC at the moment that should be taking up enough resources to be an issue. 
Next question.  If I can't synchronize number of frames during network events, then how would I proceed to keep machines synchronized?  There's got to be some way to do it, since I know for a fact that online games do manage to accomplish it.  If I play my friend in a game of Madden, for example, the ball doesn't land at different places on the different machines.  If I throw the ball, and it lands incomplete on my opponent's 10 yard line, then my opponent sees the ball land incomplete on his 10 yard line, not his 20.  That means there has to be some way to accomplish this.
NOTE:  I dropped my framerate to 50 in my game ccode to see if it would run well since it was running at 50 anyway, and this is now what I see:
Amount of real time that has passed is 10.023seconds.  DT is 0.02.  Number of frames that have passed is 435.
Amount of real time that has passed is 10.038seconds.  DT is 0.02.  Number of frames that have passed is 436.
Amount of real time that has passed is 10.037seconds.  DT is 0.02.  Number of frames that have passed is 436.
What the hell?  It ran at 50 when at 60, so I figured it'd be able to handle 50 no problem.  Now it's running at 43?  I know for a fact this machine isn't that slow.  This is really beginning to piss me the fuck off.  And I have no idea where to begin looking to try to fix the issue.
NOTE 2:  Just as I suspected, when I googled frame loss, everything I see says that what tends to cause drops of frame rate, or affect frame rate the most, is graphics.  There are no fucking graphics here.  None.  Computer specs:
Windows Version:  10.0.17134
Processor Intel(R) Core(TM) i7-4980HQ CPU @ 2.8 Ghz, 4 core(s), 8 logical processors
16 GB ram
With no graphics to worry about, that should be more than enough to not have this fucking issue.
NOTE 3:  As a test, I went into task manager and killed a bunch of unnecessary running processes to see whether freeing more RAM would change things.  Subsequent test at 50 FPS shows:
Amount of real time that has passed is 10.024seconds.  DT is 0.02.  Number of frames that have passed is 435.
Amount of real time that has passed is 10.01seconds.  DT is 0.02.  Number of frames that have passed is 435.
As you can see, nothing changed.  So what the bloody fuck?

2019-02-19 00:38:23

Yeah, I'm completely lost as to how it could possibly be that slow. Are you doing anything else while it's running? Those specs are way better than what I've got, so the results should, in theory, be better than what I got, if anything.

Both players should get the same results, starting from the same conditions. That's what the clock is for. The trick is making sure the conditions are the same when player actions are performed. In this case, it's probably sufficient for the players to agree on the ball's position and velocity when one of them acts.

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.

2019-02-19 01:31:48 (edited by JLove 2019-02-19 09:20:32)

Again, long post, so please read in its entirety.  To answer your question, nope, not doing anything else when running that test.  I even went into task manager and shut down a bunch of background processes like cortana and other windows shit, and still got 43 FPS when set to 50.
As far as players agreeing, I tried doing that initially, although I think I got it wrong.  I tried sending shot strength and direction , to the opponent when I struck the ball.  My thinking was that if the opponent has the same shot strength I do and direction, his machine would call the move method, and the ball should move the same way on both machines.  As I said before, math is immutable, so 2 + 2 will always be four.  So I figured that the formula of calculating the shot had the same values on both machines, there shouldn't be an issue.  If I have a shot strength of 5, and I hit the ball 45 degrees to the right, then if I pass shot strength to him and the direction, albeit mirroring it for sound pool, his machine should call the move method and move the same amount, given that shot strength is equal.  However, the ball was intermittently landing off by one coordinate between the two machines.  Always one coordinate, never more, and always in the direction that the ball was struck.  That might be because of the way I initially had movement running, solely based on timers.  I suspect that the timers were getting different results on both machines, and there were so many that it was causing issues.  I don't know whether changing it to the way I have it now, where it actually uses equations of physics and DT will fix that, but theoretically it should, since velocity isn't going to change based on timers.  I have removed all of the timers from my code with the exception of the one to measure DT, and the one for player movement, but that one only controls how fast the player walks, and that has nothing to do with the ball.  There are no ball timers in my code anymore.  But this frame rate issue is disturbing the hell out of me.  What the fuck is the problem?  There's absolutely nothing in my loop that should cause this level of drop.  The main game loop, with comments,  looks like this:
void CheckEvents()
{
network_event Event;
Event = Server.request();
switch(Event.type)
{
case 1:
speaker.speak("Peer has connected to server from address "+Server.get_peer_address(Event.peer_id)+".");
break;
case 2:
//So that opponent position updates correctly.
if(string_contains(Event.message, "__", 1) > -1)
{
string[] position = string_split(Event.message, "__", true);
opponent.x = string_to_number(position[0]);
opponent.y = string_to_number(position[1]);
env.update_listener_2d(opponent.x, opponent.y);
env.play_2d("sounds/step.ogg", user.x, user.y, opponent.x, opponent.y, false);
}
//Sends the shot info to the opponent so that the opponent's machine can calculate ball trajectory correctly.
if(string_contains(Event.message, ",", 1) > -1)
{
string[] NewShot = string_split(Event.message, ",", true);
opponent.NewShot(string_to_number(NewShot[0]), true);
}
//Sends the coordinates of the ball to machine 2 when user of machine one is holding the ball before the ball is tossed.
if(Event.message == "toss")
{
B.pos.x = opponent.x;
B.pos.y = opponent.y;
B.pos.z = 4;
env.play_2d("sounds/toss.ogg", user.x, user.y, opponent.x, opponent.y, false);
}
//Sends position of the ball to machine 2 at the time of serve along with relevant shot info so that machine 2 can calculate trajectory with the same values.
if(string_contains(Event.message, "::", 1) > -1)
{
string[] serveState = string_split(Event.message, "::", true);
B.pos.x = string_to_number(serveState[0]);
B.pos.y = string_to_number(serveState[1]);
B.pos.z = string_to_number(serveState[2]);
opponent.ShotStrength = string_to_number(serveState[3]);
}
break;
case 3:
speaker.speakInterrupt("Peer "+Server.get_peer_address(Event.peer_id)+" has disconnected.");
break;
}
That's all of the network stuff.  Now this is just the main loop:
C.tick();
//Testing FPS.
if(RealTime.elapsed>= 10000)
logtime();
//This is to check to see that the player serves from the correct side of the court as per the rules of tennis.
if(rules.serving)
{
if(!rules.even(rules.p))
rules.DC = true;
if(rules.even(rules.p))
rules.DC = false;
}
//To allow the move function to iterate.
if(B.moving)
B.move();
//Same for tossing the ball.
if(B.tossing)
B.toss();
//This makes sure that server never goes past 2, since only 2 players are involved.
if(server > 2)
server = 1;
//Just a fuck load of key checks, a lot of which are in here right now for testing and debugging purposes.
if(key_pressed(KEY_ESCAPE))
{
env.destroy_all();
exit();
}
if(key_pressed(KEY_T))
speaker.speak(deg + ", " + theta + ".");
if(key_pressed(KEY_D))
speaker.speak(rules.DC);
if(key_pressed(KEY_C))
speaker.speak(user.x + ", " + user.y + ". ");
if(key_pressed(KEY_O))
speaker.speak(opponent.x + ", " + opponent.y + ". ");
if(key_pressed(KEY_N))
speaker.speak("User is " + user.name + ", and opponent is " + opponent.name + ".");
if(key_pressed(KEY_RETURN))
B.GetBall();
if(key_pressed(KEY_V))
speaker.speak(V0.z + ", " + A.z + ", " + VF.z + ".");
if(key_pressed(KEY_F))
speaker.speak(C.frame);
if(key_pressed(KEY_E))
speaker.speak(RealTime.elapsed);
if(key_pressed(KEY_P))
speaker.speak(B.pos.x + ", " + B.pos.y + ", " + B.pos.z + ".");
if(key_down(KEY_LEFT))
user.move(left);
if(key_down(KEY_RIGHT))
user.move(right);
if(key_down(KEY_UP))
user.move(forward);
if(key_down(KEY_DOWN))
user.move(back);
//Key checks to toss the ball.
if(MustServe)
{
if(key_pressed(KEY_LCONTROL))
{
if(!HasBall)
{
speaker.speak("Really?  You don't have a ball, dumb ass.");
}
else
{
B.StartToss();
}
}
}
//Key check for a shot during a rally.
if(!MustServe)
{
if(key_pressed(KEY_LCONTROL) and LastShooter == 2)
user.NewShot();
//Check to insure that last shooter stays between 1 and 2, as there are only 2 players.
if(LastShooter > 2)
LastShooter = 1;
}
}
As you can see, there's nothing huge here.  Certainly nothing that should be massively draining my PC to the point that it runs at 50 FPS when set to 60, and 43 when set to 50.  If it runs at 50 FPS when set to 60, that means it should be able to run at 50 no problem when set to 50.  If you've got any ideas, or you see something massively screwed up, feel free to let me know.  I am at a loss as to the cause.  Are there any profilers outside of the BGT one that are language-independent that will work with BGT to show me what's going on with my code?  Something's happening, but I don't see where it could be.  None of my classes are huge, my game loop isn't exactly huge.  I'm just at a loss.  UPDATE NOTE:  I ran my game code just to allow for the FPS test.  I did not move the ball during this test.  I simply started the game, then sat there for around 50 seconds or so to see what the frame rate would be and to allow a profile to be generated by BGT.  The FPS test log shows:
Amount of real time that has passed is 10.027seconds.  DT is 0.02.  Number of frames that have passed is 435.
Profile results are below.  My game loop doesn't appear to be the culprit.  Look:
Profile Results
Total execution time: 53670 ms
Number of functions called: 9
void clock::tick(): 37414 ms (69.71%)
void StartMatch(bool = true): 13620 ms (25.38%)
int dynamic_menu::run_extended(string, bool, int, bool): 1351 ms (2.52%)
void main(): 1266 ms (2.36%)
void MainMenu(): 6 ms (0.01%)
void Voice::speak(string): 5 ms (0.01%)
bool logger::write(string, bool): 4 ms (0.01%)
void CheckEvents(): 2 ms (0%)
Thoughts?  I am still at a loss.

2019-02-19 14:00:27

The profiler can be misleading at times, but in this case, the only oddity that sticks out is start_match.
The vast majority of the time being in clock::tick makes sense, since that's where the calls to wait are. The dynamic_menu being high also makes sense, since its duration is better measured in seconds, what with being a loop that interacts with the user. Start_match makes sense over the others, just because of initialization and such, but I'm not sure why it would take 13 seconds, and presumably it's not still running while check events is being called.
What I did to try and isolate lag was to have timers for that purpose, and log how much time elapses in each frame. Granted, this mostly just showed me that BGT freaked out immediately after messing with sounds or doing a big bout of garbage collection, but neither of those is to blame here, so it might prove more useful, if tedious.
I'm not sure where to look, though, based on those profiler results. The profiler here gives more or less exactly the expected results. If start_match waits for a sound to play, or something like that, there's that explained, too. I guess I'd start by logging how much time passes between calls to c.tick, just to be sure that it's not something weird with the clock. From there, I'd try to divide it into something resembling half, then go whereever the data points.

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.

2019-02-19 21:34:57 (edited by JLove 2019-02-19 21:57:47)

Here's the StartMatch() function.  I probably didn't do this correctly, but:
void StartMatch(bool online = true)
{
//Sets starting values for position and Booleans that cover rules.
MustServe = true;
rules.games=0;
rules.serving=true;
m1.load("sounds/power.ogg");
server=1;
rules.serving=true;
user.x=CenterLine+1;
user.y=UserServiceLine;
opponent.x=CenterLine-1;
opponent.y=OpponentServiceLine;
//Load and set volume of the sound for the crowd.
sound ambience;
ambience.load("sounds/ambience.ogg");
ambience.volume = -10;
//Start the clock timer so that the clock actually starts at the beginning of the match.
TRestart(C.time);
//Start the timer for real time so that it corresponds with the clock timer for FPS debugging purposes.
TRestart(RealTime);
//Now initiate the loop:
ambience.play_looped();
while(true)
{
CheckEvents();
wait(5);
}
}
Again, not that huge.  Unless I massively screwed something up, I still don't see how it's causing such a big loss of frame rate.  If you see something screwed up, by all means, let me know.

2019-02-19 21:53:44

Is there a reason for the wait(5)? Strictly speaking, it shouldn't matter, because the clock waits however much time is left in the frame, and 5ms shouldn't be enough to cause issues without some other source of lag. If it isn't necessary, though, I'd try commenting it out to see what happens.
A Delay of 25ms would be 40fps, but it shouldn't be making that big a difference, if any.
I have this theory that BGT is more vulnerable to lag immediately after big RAM operations, which loading the sounds might count as. If most of the lag is happening in the first few frames, I would expect an extra delay before starting the loop to overcome it. And I'm not really convinced that this theory is correct, especially with all that RAM you have. Still, maybe a wait(1000), or a speak_wait or similar, between setting the ambience volume and restarting the timers would be enough for it to recover? Again, just a weak hypothesis based on my battles with lag a couple years ago, but if removing the wait(5) doesn't fix it, it might be worth a try.

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.

2019-02-19 21:58:13 (edited by JLove 2019-02-19 23:09:38)

Almost working now.  So close, but then on the final test...Lot of info here.  It appears that tick() was called approximately 43 times in a one-second period, but there are differences in the amount of time between iteration.  For example:
Tick called.  Elapsed real time is 0 seconds.
Tick called.  Elapsed real time is 0.046 seconds.
Then, it almost immediately gets called again:
Tick called.  Elapsed real time is 0.054 seconds.
But the next iteration doesn't happen until 0.092.  Then 0.101, 0.139, 0.148.  The pattern appears to be one call at longer intervals, followed by a very close call after, then a longer time, then a call close:  So after 0.148, the longer call at 0.185, then the close at 0.195, then the longer time at 0.231, then close at 245, then long at 277...not sure what this means.  Keep in mind that for purposes of this test, I am doing nothing but sitting.  No player movement, no movement of the ball.  I removed the wait(5).  The pattern still appears to hold with tick calls:
Tick called.  Elapsed real time is 0 seconds.
Tick called.  Elapsed real time is 0.042 seconds.
Tick called.  Elapsed real time is 0.046 seconds.
Tick called.  Elapsed real time is 0.084 seconds.
Tick called.  Elapsed real time is 0.086 seconds.
Tick called.  Elapsed real time is 0.124 seconds.
Tick called.  Elapsed real time is 0.127 seconds.
Tick called.  Elapsed real time is 0.166 seconds.
As you can see, one longer iteration, then a very short one, then a longer one.  Next, I added the wait(1000) prior to restarting the timers.  I set frame rate to 60.  This means that after each 0.016 seconds, a frame should pass.  That means that at 0.096 seconds, six frames should have passed.  Log shows:
Tick called.  Elapsed real time is 0 seconds.  Number of frames is 0.
Tick called.  Elapsed real time is 0.034 seconds.  Number of frames is 1.
Tick called.  Elapsed real time is 0.038 seconds.  Number of frames is 2.
Tick called.  Elapsed real time is 0.068 seconds.  Number of frames is 3.
Tick called.  Elapsed real time is 0.072 seconds.  Number of frames is 4.
Tick called.  Elapsed real time is 0.103 seconds.  Number of frames is 5.
The pattern still appears to hold.  Not sure why the calls to tick aren't more uniform, instead it gets called back to back virtually, then waits, then back to back, then waits.  So far, loss of one frame at 0.1 seconds.  Log at the bottom shows:
Amount of real time that has passed is 10.003seconds.  DT is 0.016666666666666.  Number of frames that have passed is 590.  So, it appears that I lose one frame every second.  What I don't understand is why the tick method basically gets called that way instead of uniformly across the board.  Is there a way to improve that?  And why now all of a sudden is this appearing to work correctly?  Even if there was initial lag after the sounds, wouldn't the first 10 seconds have shown that, say 50 FPS instead of 60, but then the next ten seconds would have shown correctly, since the lag should have been gone by then?  In other words, I can see the first ten seconds being affected by the lag, but after the sounds are loaded, the lag goes away and everything after should work correctly, right?  Besides, how the hell would loading sounds eat that much of 16 GB of ram that it lags to the point that you lose that much performance?  And after sounds are loaded, why doesn't lag go away after the first ten seconds?  It seems like Philip really, really must have screwed something up when he made BGT, or Windows has got some serious, serious issues.  NOTE:  Retesting shows the following:
Amount of real time that has passed is 10.003seconds.  DT is 0.016666666666666.  Number of frames that have passed is 604.
Amount of real time that has passed is 10.005seconds.  DT is 0.016666666666666.  Number of frames that have passed is 608.
Amount of real time that has passed is 10.009seconds.  DT is 0.016666666666666.  Number of frames that have passed is 608.
How I'm getting extra frames I don't know.  Is there a way to prevent that?  Extra frames could be an issue across machines.  Could cause the initial problem I had, ball landing differently on different cords.  Really don't want that.  NOTE 2:  This has also changed my profile results.  StartMatch now went down considerably.  Not sure why that is, since I actually added a wait there, but look:
Total execution time: 53671 ms
Number of functions called: 9
void clock::tick(): 50275 ms (93.67%)
void StartMatch(bool = true): 1482 ms (2.76%)
int dynamic_menu::run_extended(string, bool, int, bool): 1033 ms (1.92%)
void main(): 863 ms (1.61%)
bool logger::write(string, bool): 6 ms (0.01%)
void MainMenu(): 5 ms (0.01%)
void CheckEvents(): 3 ms (0.01%)
void Voice::speak(string): 2 ms (0%)
I don't understand that.  I would have thought the wait call would have lengthened StartMatch.  NOTE 3:  What, the, fuck?  So this time I decided to see what would happen in terms of frame rate if I just walked my player back and forth on the court.  Frame rate dropped a little, to 590.  But there's the question.  Looking at my profile, I see:
Total execution time: 58413 ms
Number of functions called: 11
void clock::tick(): 39733 ms (68.02%)
int dynamic_menu::run_extended(string, bool, int, bool): 14689 ms (25.15%)
The fuck?  What does moving my player have to do with the dynamic menu?  I do not call dynamic menu when I move.  When I don't move, profile looks like this:
Total execution time: 53878 ms
Number of functions called: 8
void clock::tick(): 50429 ms (93.6%)
void StartMatch(bool = true): 1480 ms (2.75%)
int dynamic_menu::run_extended(string, bool, int, bool): 1172 ms (2.18%)
So what the fuck?  Player::move looks like this:
void move(int direction)
{
if(pm.elapsed<speed)
return;
switch(direction)
{
case forward:
if(y>=net)
return;
y++;
break;
case back:
if(y<=UserBaseline-5)
return;
y--;
break;
case left:
if(x<=LeftSideline-5)
return;
x--;
break;
case right:
if(x>=RightSideline+5)
return;
x++;
break;
}
if(!OMoving)
{
env.update_listener_2d(user.x, user.y);
env.play_stationary("sounds/step.ogg", false);
}
if(OMoving)
env.play_2d("sounds/step.ogg", user.x, user.y, opponent.x, opponent.y, false);
Server.send_unreliable(0, (RightSideline-user.x)+"__"+(OpponentBaseline-user.y), Player);
pm.restart();
}
As you can see, no calls to dynamic menu.  Wht the hell?

2019-02-19 23:07:04

The pattern makes sense if something's delaying it, since the shorter delays would be the clock trying to compensate for the apparent lag. But I'm not sure that that's what's happening, given those numbers. The long frames are suspiciously close to twice as long as they should be.
Can

OK, I went and tried testing the clock by itself, and it turns out that there is a bug if the first tick happens less than delay ms after the clock was last reset. I completely failed to account for the possibility of a delay that was shorter than expected. This caused a double negative to show up in the first frame, and the oscillation you found is the result of the clock compensating without a way to prevent the problem from repeating for short frames.
I fixed it by adding this line before the call to wait in clock.bgt:
if(elapsed<0) elapsed=0;
So yeah, you found a bug in the clock. I'm not sure if this will fix the problem, since tiny variations were still happening after I fixed it, with some frames getting random extra ms even though they weren't doing anything, but it was on the order of 22ms instead of 20ms at worst, and the clock compensates for it correctly. Now, if it turns out those 1-2ms are also from a bug in the clock, I'll let you know, but it should never wait longer than delay, with that fix, so I'm assuming the noise is from my computer.

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.

2019-02-19 23:27:18 (edited by JLove 2019-02-19 23:29:46)

After adding the line, the tick appears to be called more uniformly, anywhere from  14-20 MS, and at 0.998, 59 frames passed.  I don't understand why it's ever waiting past 0.016, though, since that's what delay should be  since I've got FPS set to 60.  Not sure whether you saw what I wrote about dynamic menu and movement, but I'll post here for convenience, because I do not understand what the hell is causing this.
What, the, fuck?  So this time I decided to see what would happen in terms of frame rate if I just walked my player back and forth on the court.  Frame rate dropped a little, to 590.  But there's the question.  Looking at my profile, I see:
Total execution time: 58413 ms
Number of functions called: 11
void clock::tick(): 39733 ms (68.02%)
int dynamic_menu::run_extended(string, bool, int, bool): 14689 ms (25.15%)
The fuck?  What does moving my player have to do with the dynamic menu?  I do not call dynamic menu when I move.  When I don't move, profile looks like this:
Total execution time: 53878 ms
Number of functions called: 8
void clock::tick(): 50429 ms (93.6%)
void StartMatch(bool = true): 1480 ms (2.75%)
int dynamic_menu::run_extended(string, bool, int, bool): 1172 ms (2.18%)
So what the fuck?  Player::move looks like this:
void move(int direction)
{
if(pm.elapsed<speed)
return;
switch(direction)
{
case forward:
if(y>=net)
return;
y++;
break;
case back:
if(y<=UserBaseline-5)
return;
y--;
break;
case left:
if(x<=LeftSideline-5)
return;
x--;
break;
case right:
if(x>=RightSideline+5)
return;
x++;
break;
}
if(!OMoving)
{
env.update_listener_2d(user.x, user.y);
env.play_stationary("sounds/step.ogg", false);
}
if(OMoving)
env.play_2d("sounds/step.ogg", user.x, user.y, opponent.x, opponent.y, false);
Server.send_unreliable(0, (RightSideline-user.x)+"__"+(OpponentBaseline-user.y), Player);
pm.restart();
}
As you can see, simple, and no calls to dynamic menu.  What the hell?

2019-02-20 00:20:05

The deal with the dynamic menu is just because it's a blocking function, so all the time you spend on the menu counts. You can safely ignore it for the most part.
I'm not sure where the extra ms are coming from. I don't see how they could be bugs in the clock itself, but it's not impossible. A couple of milliseconds seems like it might just be within BGT's margin of error, but if I find anything else wrong with the clock, I'll be sure to report it.

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.

2019-02-20 05:52:40 (edited by JLove 2019-02-20 07:42:28)

In order to use the clock correctly, how exactly is the update method meant to be used?  I assume it basically returns true if a single frame has passed, right?  Just trying to figure out where to use that, or what it would be used for, since when I actually called update in the code in the past, it basically cut the amount of FPS I was getting in half.  After doing further research on using DT, apparently I need a way to keep track of the amount of time between frames, and I'm supposed to use that as DT?  I'm a little confused.  I wonder if the clock update function would be where that's used.  Something like:
double T = RealTime.elapsed;
bool update()
{
if (time.elapsed>=delay) {
double frametime = RealTime.elapsed-T;
time.restart();
time.resume();
return true;
}
return false;
}
Or something close to that.

2019-02-20 08:43:58

You don't need to worry about clock::update. I'm not sure when it would ever be needed, but it seemed possible that it might be useful at the time, so I included it just to be safe.
Not using a constant dt will result in the same problems from the beginning. The point is to keep the time passing between frames as close to constant as possible, such that the errors mostly cancel each other out before you get the scale of seconds.

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.

2019-02-22 00:35:33 (edited by JLove 2019-02-22 00:57:08)

The goal there was not to have a variable DT.  The goal was to use time correctly in the equations, then move according to DT.  According to the physics person that is helping me, this example:
VF.x = (V0.x+A.x)*DT*cosine(phi);
is incorrect.  He said that you don't use DT as the time, you use actual time, but then move by DT.  So, to determine force when the ball his hit, I think my NewShot method would need something like this:
void NewShot(double phi, double theta, bool opponentShot = false)
{
//Making sure that the shot cannot occur when rules do not apply.
if(B.pos.z == 0 or LastShooter == 1 and !opponentShot)
return;
//You can't hit the ball if you're too far away.
if(distance() > 4)
{
env.play_stationary("sounds/miss.ogg", false);
return;
}
//Get current real time.
CT = RealTime.elapsed;
//Account for some rules.
rules.shots++;
if(rules.serving)
{
rules.service++;
MustServe=false;
B.tossing=false;
LastShooter= server;
}
else
{
LastShooter++;
if(LastShooter > 2)
LastShooter = 1;
}
if(LastShooter == 1)
{
//Original values sent to opponent, will have to be changed based on new code.
string message = (deg+180) + ".";
Server.send_reliable(0, message, Ball);
}
rules.bounces = 0;
env.play_2d("sounds/shot.ogg", user.x, user.y, x, y, false);
B.rising=true;
B.moving=true;
if(rules.shots==2)
{
rules.serving = false;
rules.faults = 0;
}
//Set initial vel here, at the moment for debugging and testing purposes, will be changed later.
V0.x = 200;
V0.y = 200;
//Make sure chosen angle is correct.  Remember that he has switched it so that phi measures azimuthal angle, and theta measures elevation for some reason in this case.
A.x = SetAngle(phi);
A.y = SetAngle(phi);
Theta(B.pos.z, r);
//Now calculate time that it took to actually complete, to use in the equations, and log the value of T for debugging and testing purposes.  NOTE:  T is usually 22 or 23.
T = RealTime.elapsed-CT;
test.add_entry("T is " + T + ".");
//Set velocity using T instead of DT.
SetVel();
//This is done because the only way to get the ball sound to play correctly seems to be to have it play every x number of frames.  If you know of a better way, let me know.
C.frame = 0;
//Call move method for the ball.
B.move();
}
}
Now, in ball::move, I say:
void move()
{
//Move the ball based on velocity with DT.  I had it set velocity each time to account for the change in gravity acceleration.
pos += SetVel()*DT;
//Account for gravity.
A += G;
//For when the ball bounces.
if(pos.z <= 0)
{
moving = false;
bounce();
}
//This is done for the sound.  If I don't do it this way, the sound plays so fast that it's just a buzzing that overwhelms everything, and is why I set frames to 0 in the shot method.  Again, if you've got a better way, by all means let me know.
if(C.frame == 50)
{
B.slot = env.play_2d("sounds/ball.ogg", user.x, user.y, B.pos.x, B.pos.y, false);
C.frame = 0;
}
env.update_sound_2d(B.slot, B.pos.x, B.pos.y);
}
I hope that made sense.  If you've got any better ideas of ways to handle things, please feel free to let me know.

2019-02-22 11:00:35

I am very confused about what the actual time bit is doing and why.
Unless I missed it, there's no actual bouncing, and the ball stops once it hits the court. You'd either need to make it bounce realistically, or have the sound play on impact, and only on impact. (Or come up with a work-around that decouples the sound from movement, but that's more complicated.)
It is easy to wind up with impact sounds that rapidfire every frame. In this case, you'd need it to play only when the ball goes from falling to not falling. Gravity doesn't really care, and is still affecting the ball whether the ground is stopping it or not, so you'd either want to stop gravity from accelerating a grounded ball, or just have the bounce play if it's falling at < g*dt, where g*dt is how much vel would change in a single frame of gravity. I might even put a slight margin of error and go with 2×g×dt. ... Wait, why haven't I done this in ECTAS? That would stop knives on platforms from fall-spamming. yikes
But I'm still lost as to what they mean regarding time.

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.

2019-02-23 01:43:21 (edited by JLove 2019-02-23 01:49:29)

So, the time thing is to calculate the actual physics equations correctly.  For example, take this equation:
velocity = initial velocity plus acceleration multiplied by time
According to the person who is in physics, the initial way I did it where I did:
VF.x = (V).x+A.x)*DT...
is incorrect.  You do not multiply by DT, but rather T, actual time.  Then, when you actually move the ball, that is when you use DT.
position = velocity multiplied by DT.
That's why you need some way to actually get time.
As for the sound thing, you are confused.  I wasn't referring to sound of impact on the ball or the ball bouncing.  I was referring to the actual sound of the ball as it travels through the air.  The only way that I can think to make it work correctly is to have that sound play every x number of frames, because if I don't, the sound goes so fast that it's a buzzing that is so loud and overwhelms everything.  If I have it play every x number of frames, it plays correctly.  Not sure if there's a better way to do it.  The sound had nothing to do with impact or bouncing.  Not sure what made you think that, since when the ball hits the ground, I call a separate method entirely for bounce outside of move:
if(pos.z <= 0)
{
moving = false;
bounce();
}
This part:
if(C.frame == 50)
{
B.slot = env.play_2d("sounds/ball.ogg", user.x, user.y, B.pos.x, B.pos.y, false);
C.frame = 0;
}
Is for the ball as it travels through the air.  I hope that clears up the confusion.

2019-02-23 02:44:15

Using different values for the time passing for acceleration and movement seems ... odd, and potentially unstable.

Ah, OK, for the sound of the ball moving, you can just play it once when the ball starts moving, and have it loop, then destroy it when the ball stops. Depending on the sound, it might sound better the way you have it.

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.