Entity Screen bound checking

Started by
7 comments, last by doyleman77 12 years, 7 months ago
I have just finally changed my movement from frame based to time based, but have since experienced problems with having the enemies move out of screen space and disappear off screen.

Some lame representation here:

Player -> <-Enemies

the enemies are only able to move left, down the X axis. Their Y is randomized upon creation. The problem is, since having them run off of delta time, they may not continue past the window; example:

<-enemy || player->

where || is the far left side of the screen. If they move slow enough, they stop right at the X(0), and stay. if I up their velocity a little bit higher, they slow down at the 0, but continue to move on past the screen space until their out-of-bounds check erases them. Here's some listings from their move, and their draw, if it'll help:

Move():
void move(Uint32 dt)
{
xVel = 0.01 * dt;
x -= xVel * dt;
colBox.x = x;
colBox.y = y;
if (this->x <= -60) // is enemy off of screen?
{
tempSprite[selfIndex] = NULL;
DELETEOBJECT = this;
}
}



Draw():
void draw(SDL_Surface* dest)
{
Draw(dest, this->image, this->x, this->y);
}



the Inner Draw() function is defined in a header, and works like so:

bool Draw(SDL_Surface* destination, SDL_Surface* source, int x, int y)
{
if(destination == NULL || source == NULL)
{
return false;
}

SDL_Rect Dest_Rect;
Dest_Rect.x = x;
Dest_Rect.y = y;

SDL_BlitSurface(source, NULL, destination, &Dest_Rect);

return true;
}




I can't see any reason for this problem to pop up, and have been tinkering with this for the last good 15 hours or so.
Advertisement

If they move slow enough, they stop right at the X(0), and stay. if I up their velocity a little bit higher, they slow down at the 0, but continue to move on past the screen space until their out-of-bounds check erases them.


Why is velocity decreasing when X approaches 0? Is this by design? If not, then xVel must be getting modifying somewhere else in the code. Either that, or "dt" is being calculated incorrectly. You can try running the debugger through the Move() method to see how xVel is being calculated, or set a conditional breakpoint, or log the velocity calcs to debug window, depending on you development environment.
Your dt is of the type Uint32, which I suppose means unsigned int (32 bits). Normally a deltaTime value (or any time value for that matter) is represented with a floating point value (float or double). In addition to that, you're applying deltaTime twice, once for the velocity and the once more when you're applying the velocity. This is probably not what you intended to do? What you're essentially doing is this:

x -= xVel * dt *dt;

meaning that your code is still not frame-rate independent. In fact it will go faster with a lower frame rate (as dt gets larger with a lower frame rate).

One other small thing, assuming you're using c++, using "this->x" is not wrong but its generally accepted to just use "x". make sure to use something that works for you.

Why is velocity decreasing when X approaches 0? Is this by design? If not, then xVel must be getting modifying somewhere else in the code. Either that, or "dt" is being calculated incorrectly. You can try running the debugger through the Move() method to see how xVel is being calculated, or set a conditional breakpoint, or log the velocity calcs to debug window, depending on you development environment.


velocity doesn't decrease at all; or rather, nowhere in the code do I see it being decreased. i will try logging the variables as the ship moves towards me, and see what it produces.


thanks for the catch, jvdo; fixed the this-> and the twice application of dt.



edit:
Logged the stats, here are the last few results before and at x=0:



x:5 y:240 vel:0.09 dt:9
x:4 y:240 vel:0.09 dt:9
x:3 y:240 vel:0.08 dt:8
x:2 y:240 vel:0.09 dt:9
x:1 y:240 vel:0.09 dt:9
x:0 y:240 vel:0.09 dt:9
x:0 y:240 vel:0.08 dt:8
x:0 y:240 vel:0.09 dt:9
x:0 y:240 vel:0.1 dt:10
x:0 y:240 vel:0.09 dt:9



and the list afterwords is of course, a long list of x = 0. Maybe, because X is an int, velocity is a float, and delta time is a int, maybe it's rounding up (round towards zero)? that could explain why, if his velocity is high enough, it continues to move left.

and the list afterwords is of course, a long list of x = 0. Maybe, because X is an int, velocity is a float, and delta time is a int, maybe it's rounding up (round towards zero)? that could explain why, if his velocity is high enough, it continues to move left.


Most likely this. I would advice to change both the position and the velocity as well as the deltaTime to floating point values. Right before you're doing the drawing, cast the (float) position to an integer. This way the the object stays moving even if the speed is <1. It might not look very nice, as sometimes the objects will move one pixel and the next frame it will move two or none at all. But at least the system keeps working.

Also, I noticed that the deltaTime have a value between [8..10]. What do these values mean?? The only plausible meaning I can think if would be milliseconds; meaning that the game would run at around 100~125 fps.
A much more accurate approach would be using the real time value (for example in seconds) as a float or double.

Most likely this. I would advice to change both the position and the velocity as well as the deltaTime to floating point values. Right before you're doing the drawing, cast the (float) position to an integer. This way the the object stays moving even if the speed is <1. It might not look very nice, as sometimes the objects will move one pixel and the next frame it will move two or none at all. But at least the system keeps working.

Also, I noticed that the deltaTime have a value between [8..10]. What do these values mean?? The only plausible meaning I can think if would be milliseconds; meaning that the game would run at around 100~125 fps.
A much more accurate approach would be using the real time value (for example in seconds) as a float or double.



I am not sure I follow what you mean with real time value. are you suggesting I multiply the value by 1000?
I will update my code tonight; thank you kindly for your advice. :)

edit: yes, as I can tell, it is ms.
Multiplying the value by 1000 does not makes a whole lot of sense, this would give you the time in Micro seconds, but would still not give you any extra precision.

It is important to know what an bool, char, short, integer, float and double can store, and more importantly what it cannot store.
an integer can store values from -2,147,483,648 to 2,147,483,647. It can however only store real numbers (1, 2, 42, 1337) but no rational numbers (3.1415, 4/3, ?[font="Arial"], etc), you can uses floats or doubles for that.[/font]
[font="Arial"]For thinks like time, and distance floating point values are more natural, for graphics on a screen real numbers are more useful as it makes no sense to set half a pixel to a certain colour.[/font]

Actually, him keeping the time in miliseconds is fine, so long as he makes sure his velocity accounts for it. He can't measure time in fractions of a millisecond, so the added precision that using a float would give him is of no use.

If he divides dt by 1000 to get the time in seconds, he'd need to divide vel by 1000 to keep the speed he currently has. Or would, in theory. There's a more insidious problem he has to deal with first.

His problem is storing the position in an int. Casting a float to int eliminates everything after the decimal point. This works 'fine' when you want to decrease x. Say x starts at 10:

10 - 0.1 = 9.9 -> casted to int -> 9
9 - 0.1 = 8.9 -> casted to int -> 8

The problem is you can't represent speeds smaller than 1 pixel per frame, because decreasing x by either 0.01 or 0.9 results in the same decrease of 1.

What happens when you reach x = 0 is

0 - 0.1 = - 0.1 -> casted to int -> 0
0 - 0.1 = - 0.1 -> casted to int -> 0
0 - 0.1 = - 0.1 -> casted to int -> 0
0 - 0.1 = - 0.1 -> casted to int -> 0
...

The solution is simple, just store position as a float. This will mean that your position only changes when the accumulated vel*dt reaches 1. If you just set the position to float, however, you'll probably notice a significant slow down. That's because you calibrated speed to work at 1 pixel per frame. If you want to keep the speed as it is now, you'll need to up vel a bit.

Also, a bit of a nitpick, pi is not a rational number, it is irrational. float and double can't store it, they can however approximate it with varying degrees of precision. You could store pi as 3 in an int, even, although that would probably lead to some strange results.

Multiplying the value by 1000 does not makes a whole lot of sense, this would give you the time in Micro seconds, but would still not give you any extra precision.

It is important to know what an bool, char, short, integer, float and double can store, and more importantly what it cannot store.
an integer can store values from -2,147,483,648 to 2,147,483,647. It can however only store real numbers (1, 2, 42, 1337) but no rational numbers (3.1415, 4/3, ?[font="Arial"], etc), you can uses floats or doubles for that.[/font]
[font="Arial"]For thinks like time, and distance floating point values are more natural, for graphics on a screen real numbers are more useful as it makes no sense to set half a pixel to a certain colour.[/font]




No no, I understand that. I had totally forgot I had stored X and Y coordinates as integers, because well, I haven't looked at the parent class (sprite class) since it's implementation, some 5 months ago. sorry for the confusion!

edit: and by the pronoun that, I mean the variable storage capabilities.

This topic is closed to new replies.

Advertisement