Jump to content
  • Advertisement
Sign in to follow this  
deus.ex.nova

[C++] Calculating values only once - a game loop problem

This topic is 2642 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hey Guys,

I've been banging my head against the wall with frustration regarding this issue. I created a class that would handle the position and movement of an object in 3D space (in OpenGL), and for each time I want an object to move in real time, I need the class to calculate necessary information (e.g. initial position, initial angle, origin of orbit, etc.) and store it back in the class - but only once per movement. However the game loop presents a big issue for me. Whichever way I set up my class, the functions end up going through the loop anyways, and consequently my values calculate over and over again. Would anyone have an idea of how to solve this? sad.gif

Thanks

Share this post


Link to post
Share on other sites
Advertisement
Uh... it should be this simple:

while(game_loop_running)
{
int value = object.ComputeValueOnce();
Foo(value);
Bar(value);
Baz(value);
Quux(value);
}


Unless of course I've missed some crucial detail in your post?

Share this post


Link to post
Share on other sites

Uh... it should be this simple:

while(game_loop_running)
{
int value = object.ComputeValueOnce();
Foo(value);
Bar(value);
Baz(value);
Quux(value);
}


Unless of course I've missed some crucial detail in your post?


Here are the contents of the loop (the loop exits if the ESC key is pressed):
// Is updating program data going fine?
if( gameLoop.UpdateContent() != 0 )
return -1;

// Is drawing going fine?
if( gameLoop.DrawScene() != 0 ) // Draw The Scene
return -2;
SwapBuffers(hDC); // Swap Buffers (Double Buffering)


The UpdateContent() function looks something like this:

int GameLoop::UpdateContent()
{
RegisterKeys(); // check for key presses

stars.MoveDot();

ballMotion.SetDestination( ... );
ballMotion.MoveCurved( ... );

return 0;
}


Since SetDestination() always supposed to have the same value as the program loops, it's not an issue. My MoveCurved function however, moves an object along a constant, circular curve. First it needs to calculate where the center of the invisible circle is according to two points that the object should intersect. Since the points remain the same for a particular function call, the center of the circle remains the same - in other words it's not an issue with the game loop.

Here's where the problem starts. I use parametric equations that tell me where the x and z coordinates should be depending on an angle. In order to move the object, I change the angle. I don't care where the object stops moving so much as where it starts moving from. It's all fine and dandy when I set my current angle as the initial angle in the function, but as the game loop goes through, my current angle just resets back as the initial angle again and again. How do I have it where the current angle is assigned the value of the initial angle once. Would I just have to declare another instance of my ObjectMotion class any time I want the object to move differently while the program is running? Thanks, again.

Share this post


Link to post
Share on other sites
I think I may have understood your question backwards... so what you want is to incrementally change the start angle every time you run through the loop?

int value = GetInitialValue();

while(game_loop_running)
{
RenderUsingValue(value);
value = UpdateValueStartingFrom(value);
}



Maybe it'd help if you posted your actual code...

Share this post


Link to post
Share on other sites

I think I may have understood your question backwards... so what you want is to incrementally change the start angle every time you run through the loop?

int value = GetInitialValue();

while(game_loop_running)
{
RenderUsingValue(value);
value = UpdateValueStartingFrom(value);
}



Maybe it'd help if you posted your actual code...


Pretty much, yes. I also want to be able to chain different movements together (e.g. object curves around then goes straight). So far it seems almost like I have to make multiple game loops. Sorry, this is quite a bit of code to go through, and there is some bits of unused code that needs to be taken out. Please feel free to chew me out for doing anything dumb. I'm a self-taught programmer and I'm definitely willing to learn from the professionals. wink.gif

main.cpp (most of this code is from the NeHe OpenGL Tutorials

while(!done) // Loop That Runs While done=FALSE
{
if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) // Is There A Message Waiting?
{
if (msg.message==WM_QUIT) // Have We Received A Quit Message?
{
done=TRUE; // If So done=TRUE
}
else // If Not, Deal With Window Messages
{
TranslateMessage(&msg); // Translate The Message
DispatchMessage(&msg); // Dispatch The Message
}
}
else // If There Are No Messages
{
// Draw The Scene. Watch For ESC Key And Quit Messages From DrawGLScene()
if (active) // Program Active?
{
if (keys[VK_ESCAPE]) // Was ESC Pressed?
{
done=TRUE; // ESC Signaled A Quit
}
else // Not Time To Quit, Update Screen
{
// Is updating program data going fine?
if( gameLoop.UpdateContent() != 0 )
return -1;

// Is drawing going fine?
if( gameLoop.DrawScene() != 0 ) // Draw The Scene
return -2;

SwapBuffers(hDC); // Swap Buffers (Double Buffering)
}
}

if (keys[VK_F1]) // Is F1 Being Pressed?
{
keys[VK_F1]=FALSE; // If So Make Key FALSE
KillGLWindow(); // Kill Our Current Window
fullscreen=!fullscreen; // Toggle Fullscreen / Windowed Mode
// Recreate Our OpenGL Window
if (!CreateGLWindow("Flow Field & Collision Detection",global.monitorResolutionWidth,global.monitorResolutionHeight,32,fullscreen))
{
return 0; // Quit If Window Was Not Created
}
}
}
}


GameLoop.cpp:
GameLoop::GameLoop()
{
stars = DotField( 0.0f, 0.0f ); // alpha and heading degrees set to 0
ball = Sphere( stars.global.ScaleCmToPixels(23.8506f), 50, 50); // Creates a Sphere object, basketball 23.850 6 cm
ballMotion = ObjectMotion( 0.0f, 0.0f, -stars.global.zDepth);
}


GameLoop::~GameLoop()
{

}


int GameLoop::UpdateContent()
{
RegisterKeys(); // check for key presses

// move dots; enable switching motion on and off
if ((stars.global.dotMotionSwitch % 2) == 0)
{
stars.MoveDot();
}

// move ball; enable switching motion on and off
if ((stars.global.sphereMotionSwitch % 2) == 0)
{
ballMotion.SetDestination( 0.0f, 0.0f, -stars.global.zObserver - 50.0f );
ballMotion.MoveStraight(stars.global.ScaleCmToPixels(stars.global.dotSpeed));
if( ballMotion.MoveCurved( ballMotion.SpeedPerFrame(5.0f), ballMotion.XYZDistance() / 2.0f, 1) != 0 )
return -1;
}

return 0;
}


int GameLoop::DrawScene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer

SetRenderingContext( Dots );

stars.Draw();

SetRenderingContext( Ball );

ball.Draw( ballMotion.XPos(), ballMotion.YPos(), ballMotion.ZPos() );

glLoadIdentity(); // Reset The Current Modelview Matrix

return 0; // Everything went okay
}



Sorry, this is quite a bit of code to look through

ObjectMotion.h
#include "Global.h"

class ObjectMotion
{
public:

// MEMBER FUNCTIONS

ObjectMotion(const float &xPos = 0.0f, const float &yPos = 0.0f, const float &zPos = 0.0f); // ObjectMotion constructor

~ObjectMotion(); // ObjectMotion destructor

float XPos() const;

float YPos() const;

float ZPos() const;

float XYZDistance() const;

void SetPosition(const float &xPos, const float &yPos, const float &zPos);

void SetDestination(const float &xPos, const float &yPos, const float &zPos);

void PrepForNewMove(); // resets movement func call-counter for necessary calcs; call just before calling a movement func

void MoveStraight(const float &velocity); // moves the sphere in a linear trajectory

int MoveCurved(const float &angularVelocity, const float &radiusOfCurve, const bool &CCW = false); // moves the sphere in a curved trajectory

bool IsObjectInViewport() const; // check if ball is in the viewport


private:

struct Vector3f // structure holding coordinates
{
float x, y, z;
};

Vector3f position; // the current coordinates of the object
Vector3f destination; // the destination of the object

Vector3f axis; // the center of rotation or orbit of object
float midpoint;
float initialAngle;

// Total distance in terms of each axis
float xDistance;
float yDistance;
float zDistance;
float xyzDistance; // Total distance of entire vector

// Velocity in terms of each axis; also represents how much position increments each frame
float xVelocity;
float yVelocity;
float zVelocity;

float eta; // time of arrival to destination
int callCounter; // tracks how many times function is called

Global global;

float DegToRad(const float &degrees) const;

float RadToDeg(const float &radians) const;

float SpeedPerFrame(const float &speed) const; // returns speed that will sync with frames

int SetAxis( const float &radiusOfCurve, const bool &CCW = false );

void SetInitialAngle( const float &radiusOfCurve);
};



ObjectMotion.cpp
int ObjectMotion::MoveCurved( const float &angularVelocity, const float &radiusOfCurve, const bool &CCW )
{

if( SetAxis(radiusOfCurve, CCW) )
return -1;

SetInitialAngle( radiusOfCurve );

if( IsObjectInViewport() )
{
switch(CCW)
{
case false:
initialAngle -= angularVelocity / 60; // initialAngle is initial angle value in unit circle (radians); "60" fps
break;
case true:
initialAngle += angularVelocity / 60;
break;
}

position.x = axis.x + xyzDistance * cos( initialAngle ); // totalDistance is the vector between ball and destination
position.z = axis.z - xyzDistance * sin( initialAngle ); // axis is the center around which the curve moves
}

return 0; // Everything went okay
}


int ObjectMotion::SetAxis( const float &radiusOfCurve, const bool &CCW )
{
// find midpoint, inverse of position-destination slope, distance btwn pos/dest and midpoint, and z intercept of inverse line
Vector3f midpoint = { (position.x + destination.x) / 2.0f, 0.0f, (position.z + destination.z) / 2.0f };
float slope;
if( position.z - destination.z == 0 ) // Check if the the slope exists
slope = midpoint.x;
else
slope = -(position.x - destination.x) / (position.z - destination.z);
float posToMidDist = sqrt( pow(position.x - midpoint.x, 2) + pow(position.z - midpoint.z, 2) );
float zIntercept = midpoint.z - (slope * midpoint.x);

// make sure radius is great or equal to half the distance between position and destination
// otherwise, exit the program
if( radiusOfCurve < posToMidDist )
return -1;

switch(CCW) // change calcs depending on clockwise or counterclockwise motion (i.e. axis on opposite side)
{
case false:
axis.x = midpoint.x - sqrt( (pow(radiusOfCurve, 2) - pow(posToMidDist, 2)) / (1.0f + pow(slope, 2)) );
axis.y = 0.0f;
axis.z = (slope * axis.x) + zIntercept;
break;

case true:
axis.x = midpoint.x + sqrt( (pow(radiusOfCurve, 2) - pow(posToMidDist, 2)) / (1.0f + pow(slope, 2)) );
axis.y = 0.0f;
axis.z = (slope * axis.x) + zIntercept;
break;
}

return 0; // Everything went okay
}


void ObjectMotion::SetInitialAngle( const float &radiusOfCurve )
{
Vector3f midpoint = { (position.x + destination.x) / 2.0f, 0.0f, (position.z + destination.z) / 2.0f }; // find midpoint of the two point
float posToMidDist = sqrt( pow(position.x - midpoint.x, 2) + pow(position.z - midpoint.z, 2) ); // find distance between position point and midpoint
float posToAxisDist = sqrt( pow(position.x - axis.x, 2) + pow(position.z - axis.z, 2) ); // find distance between position point and axis

initialAngle = 2.0f * asin( posToMidDist / posToAxisDist );
}

Share this post


Link to post
Share on other sites
Well, the overly simplistic answer is that you're calling SetInitialAngle() every time you call MoveCurved(). If you don't want the movement to change the initial angle, just... stop doing that :-)

Share this post


Link to post
Share on other sites

Well, the overly simplistic answer is that you're calling SetInitialAngle() every time you call MoveCurved(). If you don't want the movement to change the initial angle, just... stop doing that :-)


So where should I call SetInitialAngle? Outside the game loop? If I did call SetInitialAngle outside of the game loop, what happens when I want to then move the object in a different curve?

Share this post


Link to post
Share on other sites
You call SetInitialAngle precisely in those situations when you want to change the initial angle value. Maybe that's during initialization of your game, maybe that's later when it comes time to change the movement path, maybe some combination involving other scenarios I haven't thought of yet. The point is your function can be called whenever you need that effect (i.e. to change the initial angle). Nobody's holding a gun to your head saying "do it inside the game loop every time, or outside just once" ;-)

Share this post


Link to post
Share on other sites

You call SetInitialAngle precisely in those situations when you want to change the initial angle value. Maybe that's during initialization of your game, maybe that's later when it comes time to change the movement path, maybe some combination involving other scenarios I haven't thought of yet. The point is your function can be called whenever you need that effect (i.e. to change the initial angle). Nobody's holding a gun to your head saying "do it inside the game loop every time, or outside just once" ;-)


I understand what you're saying. I just...haven't been able to figure out where to put it while having it as part of the class. At some point I wanted to be able to press a button that would give me a different set of points, and therefore a different initial angle and different curve that the object would move on. *sigh*... ( ._.) Maybe I just need to take a break from this, and then totally revamp my code when I come back to it...

Share this post


Link to post
Share on other sites

I just...haven't been able to figure out where to put it while having it as part of the class.


I'm not sure what you mean by this? "It" (being the SetInitialValue function) is already part of the class. You can call it from wherever you want, even from other classes. There's nothing wrong with that.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!