Advertisement

Strange problem...

Started by June 16, 2004 01:26 AM
13 comments, last by discman1028 20 years, 5 months ago
Hey all, working on a game and just came across a strange problem. Without pouring code all over you, I'll explain as best I can.. I made a vector class, and a member function set(x,y,z) to set a vector's values. This function works. Now, in renderScene() (glut callback), I call a car.update() function (member function, where 'car' is a global <global for now> instance of a vehicle clas). This update definition, among other things, has in it, "gravForce.set(0.0,-9.81*mass,0.0)", where mass and gravForce are members of the vehicle class. Ignoring the way I am tesing out this function, read on. What I want this to do is have a constant grav force, and any vehicle onscreen falls. When I put "gravForce.set(0.0,-9.81*mass,0.0)" inside an else statement, everything works fine.. the car falls. This else statement, by the way, only gets executed when it receives input from the user. Hmmm. I tried it in there, because what I describe below didn't work: Putting it in the main body of update(), everything goes to hell: the position of the car jumps to a huge number (2157..........), and its acceleration to too high of a number also. And the model is gone. This may not be enough info, but any immediate thoughts? Thanks! --== discman1028 ==--
--== discman1028 ==--
Do you have anything to stop the car from falling down.. such as the ground? or the bottom of the screen? If not, it could simply overflow and you could find yourself with bizarre numbers. Also, is the (-9.81*mass) the speed you are using?
Disclaimer: "I am in no way qualified to present advice on any topic concerning anything and can not be held responsible for any damages that my advice may incurr (due to neither my negligence nor yours)"
Advertisement
Impossible to tell without more information, please post some relevant code.

Enigma
Since gravity is a global phenomenon (as opposed to being the characteteristic of each separate vehicle), you should make it a global variable, not keep it as a member attribute.

Consider this:

class TEnvironment{   public:      TVector Gravity;      TVector WindSpeed;//.... etc} Env;class TVehicle {  public:     float AreaXY;     TVector Origin;     float Mass;}class TCar : public TVehicle{  //possibly some car specific parameters}void DoFunkyFreefall(TVehicle * Vehicle, TVector Gravity){  //do freefall}int main(){  TVehicle* Car = new TCar();  Car->Origin.Set(0, 0, 0);  Car->Mass = 890;  Env.Gravity.Set(0, -9.81, 0);  DoFunkyFreefall(Car, Env.Gravity);}


This is how I'd do it, anyway... Hope this helps!
"Literally, it means that Bob is everything you can think of, but not dead; i.e., Bob is a purple-spotted, yellow-striped bumblebee/dragon/pterodactyl hybrid with a voracious addiction to Twix candy bars, but not dead."- kSquared
Crispy: Good point, but (assuming single environment) I would make it...
class TEnvironment{   public:      static const TVector Gravity;      static const TVector WindSpeed;//.... etc};const TVector TEnvironment::Gravity(0, -9.81f, 0);const TVector TEnvironment::WindSpeed(/*whatever*/);class TVehicle {  public:     float getAreaXY() const;     // other get methods     void setAreaXY(float newAreaXY);     // other set methods  private:     float AreaXY;     TVector Origin;     float Mass;}class TCar : public TVehicle{  //possibly some car specific parameters}void DoFunkyFreefall(TVehicle& Vehicle, TVector Gravity){  //do freefall}int main(){  TVehicle Car;  Car.setOrigin(0, 0, 0);  Car.setMass(890);  DoFunkyFreefall(Car, TEnvironment::Gravity);}


Reasons:
Gravity, WindSpeed etc. are static const members because you only need a single copy of each and they should not be changed by the application (assuming that a static environment). If gravity was constant and windspeed was not then I would probably split them between two classes - one for constants and one for variables (providing there were sufficient variables to warrant this).

Getter and Setter methods used in vehicle to allow constraints to be enforced (i.e. Mass > 0, AreaXY >= 0).

Car passed by reference to eliminate bad pointer problems and the memory pool your code had because it never deleted the Car (Yes, I realise it was just example code [smile]).

Enigma
This is a purely structural problem and the way you add intreface functions to your classes (such as TVehicle::setMass() ) is completely up to you and how much additional code you're willing to write.

There are quite a few environmental variables that you can either group or keep separately. Many of these variables are, of course, constant, but only if you consider a case where they can be constant (such as gravity, up vector, etc) while others are true mathematical constants (pi, Euler's number, Avogadro's number, etc). Then there's variables that are usually not constant (such as wind speed and direction, amount of precipitation, etc). I personally would group both such non-mathematical constants as well as other variables if they are directly related.

Besides, gravity in a physics demo, doesn't really have to be represented by a constant vector - a much more plausible way would be to keep gravity as a simple global floating number and apply it according to the directional relationship between two objects (depending on how you look at it, the Earth doesn't always pull you downwards, does it now).
"Literally, it means that Bob is everything you can think of, but not dead; i.e., Bob is a purple-spotted, yellow-striped bumblebee/dragon/pterodactyl hybrid with a voracious addiction to Twix candy bars, but not dead."- kSquared
Advertisement
My post was meant to be a reinforcement of your point about making gravity a global rather than a criticism of your code. Sorry if it seemed otherwise. I just like to promote "good" programming practice (not to say that yours isn't good) whenever possible, for the benefit of less experiences programmers who may view these posts.

Many newer C++ programmers have great problems with pointers and tend to make all member variables public for convenience. There was absolutely nothing wrong with the code you posted (well, apart from the memory pool [wink]) My changes were simply an attempt to make it more n00b-friendly, if you'll pardon the expression.

Enigma
the function is simply being called at a quicker rate than it should be, it should be called once per second, it is likely that you are calling it once or more per frame, dont do this. The best fix is to calculate the aproximate frames per second that you are getting, and divide the -9.81 by this number. This will make the acceleration more parabolic than simply only calling it once per second.
To answer most of you: I know this isn't the best way to implement gravity... remember I said "Ignoring the way I am tesing out this function"... but it works inside an else statement..


Anonymous Poster and all: I am updating the car's position every frame, as well as setting this 'gravForce.set(0.0,-9.81*mass,0.0)' every frame, and the vehicles move according to a = F/m, V = Vo + a*dt, etc. (I'm using time-based movement)

Enigma: I completely understand your organization. That's not what I was immediately looking for but that might do it and might be a better way to organize it all anyhow.

Another question: About overall organization.. I am trying to make the main() as simple as possible. This is what I have, I'm wonering if you have major suggestions before I move on. I don't have experience in coding large programs...I get messy and pretend I'll fix it later :) Here's the renderScene():

{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
gluLookAt(.......);

glPushMatrix();

car_1.update(KeyDown['w'],KeyDown['s'],KeyDown['a'],KeyDown['d']); /* (There are only four controls right now... gas, reverse, left, right. Vehicle class handles the rest..) */

car_1.drawModel();
glPopMatrix();

debugOutput(); // Shows debugging info
glutSwapBuffers();
glutPostRedisplay();
findFrameRate(); // Do this every loop
}




Well, that's about it. Organization ideas? Maybe a class structure idea? This won't be getting too complex: I have a terrain class (terrain.h) for loading a map, and will (hopefully) work its collision detection with the variables in vehicle.h.



Thanks for all your input.
--== discman1028 ==--
... And looking at my post, I guess it is kind of silly giving you the renderscene and asking for class-structure suggestions.

I have: main.cpp at the top

It includes vehicle.h only.

Vehicle.h includes model.h and milkshapemodel.h, along with:

vector.h // Vector class
timer.h // For FPS calculation/time-based movement
terrain.h // For loading a map, and later interacting with vehicle class
wheel.h // My class... not sure if wheels belong separately. They are in a separate class, but separate file may be a bit much.



Thanks again.
--== discman1028 ==--

This topic is closed to new replies.

Advertisement