move sprite


void move(int v)
{
	move_right++;

	if (move_right >= 9.0f)
	{
		move_right = 9.0f;
	}
	drawScene_bug_two(move_right, 10.0f);
	glutPostRedisplay();
	glutTimerFunc(1000, move, 0);
}

void drawScene() {
	glClear(GL_COLOR_BUFFER_BIT);
	bullet();
	drawScene_bug_one(-2.0f, 10.0f);
	move(0);
	glutTimerFunc(1000, move, 0);
	coll_bug_one();
	erase_sprite();
	drawScene_ship_one();
	glutSwapBuffers();
}

I am able move my sprite from the center to the right border. but it moves very quickly, I want it to move slowly and one sprite width at a time. just like in space invaders.

can I please get some input

As you wish. If I did not mess something up, here is my analysis why your Sprites are moving to fast:

You are using:

move_right++;

I guess move_right should represent your x-position. So you increase your position value every time you call your move function. Now there are 2 questions to me:

  • How often is your function called?
  • How much do you increase your value when using the operator ++?

This is important since both influence the time dependent position of your object. The answer to question 1 is expected to be 1 time per second (glutTimerFunction with 1000ms delay). The answer to question 2 is probably “by 1” like for integers (not sure here since I never tested it on floats … 7 years cpp and I am not sure xD).

So if your function is called once per second you end up at your limit of 9.0 after 9 seconds. Sounds quiet slow and this is probably what you want to happen. So if it is faster than that, one answer to the questions must be wrong. Since I doubt that the ++ operator is doing something unexpected here your function must be called more often than expected.

So check your code for the calls to move():


void move(int v)
{
	move_right++;
 
	if (move_right >= 9.0f)
	{
		move_right = 9.0f;
	}
	drawScene_bug_two(move_right, 10.0f);
	glutPostRedisplay();
	glutTimerFunc(1000, move, 0);               // call to move after a delay of 1 second
}
 
void drawScene() {
	glClear(GL_COLOR_BUFFER_BIT);
	bullet();
	drawScene_bug_one(-2.0f, 10.0f);
	move(0);                                   // call to move
	glutTimerFunc(1000, move, 0);              // call to move after a delay of 1 second
	coll_bug_one();
	erase_sprite();
	drawScene_ship_one();
	glutSwapBuffers();
}

So every time you call drawScene move is called twice. This doubles your increment of your position to 2 per drawScene() call. I guess you are calling drawScene more often than just once. Now your average movement speed per second is: 1 * 2 * numberOfTimesDrawSceneIsCalledPerSecond.
Additionally your move function is calling itself again (delayed) and here lies the major problem! If you were calling move just a single time from outside, your sprites position would be increased by 1 every second. If you would call drawScene just a single time your position would already be increased by 2 every second since you called move twice and every call to move triggers another delayed call. So basically your move function is a “accelerate by 1” function. If you call drawScene multiple times you will accelerate even more.

So the easiest fix would be to remove the calls to move from drawScene and call it only once before entering your main loop.
I think a better and more flexible approach is to use STL chrono lib instead of the glutTimerFunc. Just measure the time that has passed since the last call to move in your drawScene function. If it is more than 1000ms, call move and restart the counter.

Greetings

well here is my chrono code


void delay()
{
	auto start = chrono::high_resolution_clock::now();
	drawScene_bug_two(move_right, 10.0f);
	auto end = chrono::high_resolution_clock::now();
	chrono::duration<double> diff = end - start;
	cout << diff.count() << endl;
}

I am unsure of how to implement this code into my game.


void move(int v)
{
	move_right++;

	if (move_right >= 9.0f)
	{
		move_right = 9.0f;
	}
}

void drawScene() {
	glClear(GL_COLOR_BUFFER_BIT);
	bullet();
	drawScene_bug_one(-2.0f, 10.0f);
	drawScene_bug_two(move_right, 10.0f);
	glutTimerFunc(1000, move, 0);
	coll_bug_one();
	erase_sprite();
	drawScene_ship_one();
	glutSwapBuffers();
}

well here is my updated code using glutTimerFunc, it pauses for a second and then accelerates to the edge of the screen.

[QUOTE=pbivens;1291997]


void move(int v)
{
	move_right++;

	if (move_right >= 9.0f)
	{
		move_right = 9.0f;
	}
}

void drawScene() {
	glClear(GL_COLOR_BUFFER_BIT);
	bullet();
	drawScene_bug_one(-2.0f, 10.0f);
	drawScene_bug_two(move_right, 10.0f);
	glutTimerFunc(1000, move, 0);
	coll_bug_one();
	erase_sprite();
	drawScene_ship_one();
	glutSwapBuffers();
}

well here is my updated code using glutTimerFunc, it pauses for a second and then accelerates to the edge of the screen.[/QUOTE]

Well the problem is probably that drawScene is called more than once per second. So every time you call drawScene you start a new timer that should call move after a second. Lets say drawScene is called 10 times a second. Then nothing will happen for a second because no timer has triggered yet. After the second 10 timers will call move one after each other over the period of the next second. Result is a movement speed of 10 in second number 2. As I said, I think the glutTimerFunc is the wrong tool for your use case.

What you need to do is the following: Write a function which gives you the passed time since your program started as an integer value. You will find a lot of examples in the internet. The funtion interface might look like this:


int GetElapsedTime()
{
    // ... some STL chrono magic to return the elapsed time in milliseconds
}

Now before you enter your main loop, declare a variable and initialize it as follows:


int refTime = GetElapsedTime();

Then put the following lines into your drawScene function:


if(GetElapsedTime() - refTime > 1000)
{
    move(0);
    refTime += 1000;
}

I hope I did not mess anything up but I think you get the intention. You will only call move if the time difference between your refTime and the current time is bigger than one second. Additionally you will now add one second to your refTime so that the condition is only fulfilled after another second has passed. If that works you can also remove the unnecessary parameter from your move function interface.

Greetings

some STL chrono magic to return the elapsed time in milliseconds

Please do not do this. I know that Chrono seems like magic to a lot of people, but it really isn’t. And if you learn it, you’ll never, ever, have to ask the question, “what units is this time delta in again?”

The first rule of std::chrono is never stop using chrono. That is, if you want to have a function return the current time since the clock’s epoch milliseconds, you do it by returning a tick count in milliseconds:


std::chrono::milliseconds GetTime()
{
  return std::high_resolution_clock::now().time_since_epoch();
}

Never return naked integers. Never use naked integers when dealing with time.

So your refTime is a std::chrono::milliseconds too. And your condition check ought to be:


using std::chrono::literals;

if((GetTime() - refTime) > 1000ms)
{
    move(0);
    refTime += 1000ms;
}

See how much more readable that is? You never have to guess that GetTime returns milliseconds; it tells you what it returns. Even better, if you want to change GetTime to provide microsecond-accuracy, you can, and all the rest of the code will still work.


int time()
{
	using namespace std::chrono;
	auto now = high_resolution_clock::now();
	auto millis = duration_cast<milliseconds>(now.time_since_epoch()).count();
	cout << millis << endl;
	return millis;
}

well here is my chrono code, how do I incorporate this into my game code.

I’m not sure I understand. I was basically just filling in ProgrammerX’s “GetElapsedTime” code. Everything else is as he suggested.

And you still didn’t follow my recommendation about not converting to integers when handling times.

well I thought my code is converting the clock to integers.

Your code is doing that. I’m saying you shouldn’t be doing that. An integer is a typeless quantity. If you see a naked integer somewhere in your code, you have no idea if that’s in seconds, milliseconds, microseconds, etc.

Time durations should always have a unit attached to them.

[QUOTE=Alfonse Reinheart;1292003]Please do not do this. I know that Chrono seems like magic to a lot of people, but it really isn’t. And if you learn it, you’ll never, ever, have to ask the question, “what units is this time delta in again?”
[/QUOTE]

You are right, chrono is no magic, I just wrote this comment, because I was too lazy to google the right source code :wink: . Regarding your statements concerning units: I totally get your point and (partially) agree.
The problem here is, that the TO seems to be quiet new to C++/OGL. All the chrono related commands really bloat the code, since they are usually quiet long. So I think it would be easier for the TO to work with data types which he already knows. In my point of view the best solution would be to write a timer class which handles the chrono stuff inside and provides functions to get the elapsed time in some common time units


int GetElapsedSeconds() const;
int GetElapsedMilliseconds() const;
int GetElapsedMicroeconds() const;

Additionally you use a reset function to restart the timer. Using this with the TOs original problem you get something like:


void drawScene()
{
... 
if (timer.GetElapsedMilliseconds() >= 1000)
{
    timer.Reset();
    move();
}
...
}

That’s at least how I handle timed events most of the time. Properly named functions ensure that you won’t mess up the units and the class itself hides all the chrono work.

@pbivens: Does it work now as expected? If yes, you should think about the advise of Alfonse (since he has a valid point) and if or how you want to include it. It would make the code a little bit more complicated, but adds another layer of security. I think the best thing would be if you start with object oriented programming and write a timer class. It’s additional work, but it makes your life much easier.

The problem here is, that the TO seems to be quiet new to C++/OGL.

But that’s the perfect time to learn how to do these things right. Would you suggest that a new C++ user avoid std::vector<int> when creating a dynamic array, knowing that they will have to deal with delete[] complexity? Would you suggest a new C++ user avoid std::array<int, 10> and instead use an int var[10];, knowing that they have to deal with the fact that it decays into a pointer, can’t be compared to other arrays, can’t be directly copied, and other C-style array issues?

I would hope not. The standard library has an excellent tool for times that is simple to use and pretty much impossible to break. And the more widely you use that tool, the more powerful and safe your code gets. It may be more verbose in places, but I’m pretty sure that new users can handle that. Don’t underestimate them.

Properly named functions ensure that you won’t mess up the units and the class itself hides all the chrono work.


std::chrono::duration<int, microseconds> GetTime();

Is just a self-documenting. And thanks to auto, you don’t even have to remember the longer name.

This is self-documenting too: timer.GetTime() &gt;= 1000ms. It’s also much shorter.

[QUOTE=Alfonse Reinheart;1292031]But that’s the perfect time to learn how to do these things right. Would you suggest that a new C++ user avoid std::vector<int> when creating a dynamic array, knowing that they will have to deal with delete[] complexity? Would you suggest a new C++ user avoid std::array<int, 10> and instead use an int var[10];, knowing that they have to deal with the fact that it decays into a pointer, can’t be compared to other arrays, can’t be directly copied, and other C-style array issues?

I would hope not. The standard library has an excellent tool for times that is simple to use and pretty much impossible to break. And the more widely you use that tool, the more powerful and safe your code gets. It may be more verbose in places, but I’m pretty sure that new users can handle that. Don’t underestimate them.


std::chrono::duration<int, microseconds> GetTime();

Is just a self-documenting. And thanks to auto, you don’t even have to remember the longer name.

This is self-documenting too: timer.GetTime() &gt;= 1000ms. It’s also much shorter.[/QUOTE]

You are probably right. I have never put that much thoughts in using the chrono lib because it wasn’t necessary. I like your suggestions about the GetTime function. I think I will change my own code in favor of this solution. The TO should do this as well.

Greetings

what is TO

Thread opener :wink:

how do I reset my timer?

Basically the way we told you before. You just need to wrap everything into a class. You should probably start learning object oriented programming.

What do you mean by “resetting” your timer? That is, what do you want to happen? Are you trying to pause the timer or something? Do you want your object to go back to the first position (FYI: that’s not controlled by the timer; it’s controlled by things that read from the timer)?

He wants to know how can restart a timer class which gives you the elapsed time since a certain point in time. So he can do basically this


if(timer.GetTime() >= 1000ms)
{
    move();
    timer.Reset();
}

The answer to this question are basically given by previous posts. He just needs to wrap it into a class.