My Collision detection stopps working

Oct 13, 2019 at 9:34am
Hi i wrote really basic collision detection .Called (Pixel Perfect Collision Detection)but when i go backwards in game collision detection stops working.
Why this happens and how to fix.

Collision detection stops working after pressing "s" (backward key" on keyboard

My snippet:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include<stdio.h>
#include <gl/glut.h>
#include <math.h>
#define KEY_ESC 27 /* GLUT doesn't supply this */
float tra_x = 0.0f;
float tra_y = 0.0f;
float tra_z = 2.0f;

...
void display(void)
{
...

   if ((tra_x == 0.1f || tra_x == 0.2f|| tra_x == 0.3f|| tra_x == 0.4f|| tra_x == 0.5f|| tra_x == 0.6f || tra_x == -0.0f|| tra_x == -0.1f|| tra_x == -0.2f)&& (tra_z == 2.0f) ){

tra_z-=0.1f;

glutPostRedisplay();


}

...

}
...
void Keyboard(unsigned char key, int x, int y)
{
switch(key)
	{
		case 27 : 
			exit(1); 
			break;

			

		case 'w':
		case 'W':
		
			tra_x += 0.1f;
			
	


			
			break;
			
		case 's':
		case 'S':
		tra_x-=0.1f;


			break;
		case 'a':
		case 'A':
			tra_z -= 0.1f;
			
			break;
		case 'd':
		case 'D':
			tra_z += 0.1f;
		
			break;
	
			

	}

	
	glutPostRedisplay();
}
Last edited on Oct 13, 2019 at 9:34am
Oct 13, 2019 at 9:41am
> if ((tra_x == 0.1f || tra_x == 0.2f|| tra_x == 0.3f|| tra_x == 0.4f|| tra_x == 0.5f|| tra_x == 0.6f || tra_x == -0.0f|| tra_x == -0.1f|| tra_x == -0.2f)&& (tra_z == 2.0f) ){
Yeah, never compare floats for equality.
http://c-faq.com/fp/fpequal.html

0.1 for example has no EXACT binary representation, so there's no guarantee that a round trip of successively adding and subtracting 0.1 will ever get you back exactly to where you started.

You'll get back to approximately where you started.
Oct 13, 2019 at 9:50am
still not works
Last edited on Oct 13, 2019 at 10:41am
Oct 13, 2019 at 9:55am
I TRIED IT NOW GAME PUSHES me from map really fast code not works
if(fabs(tra_x - tra_z) <= 20 * fabs(tra_x))
{

tra_z-=0.1f;

glutPostRedisplay();


}

also i got 500 fps its weird

Edit i reached 1000 fps
Last edited on Oct 13, 2019 at 9:59am
Oct 13, 2019 at 10:41am
how i can fix
Oct 13, 2019 at 12:33pm
As noted by salem c floating points should not be compared, but there is a way to do it!

Here is a method which I use to compare floats (including comment on how to use it):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
	/**
	* Compares if two floating point numbers are equal.
	* comparison precision is governed by epsilon value,
	* lower the epsilon more accurate the result
	*
	* @param param1		first value used for comparison
	* @param param2		second value used for comparison
	* @tparam FType		floating point type ie. float, double or long double
	*
	* @return			true if given floating point values are equal
	*/
	template<typename FType>
	bool compare_float(FType param1, FType param2, FType epsilon) noexcept
	{
		// Calculate the difference.
		const FType diff = std::abs(param1 - param2);
		param1 = std::abs(param1);
		param2 = std::abs(param2);

		// Find the largest
		const FType largest = (param1 > param2) ? param1 : param2;

		const FType temp = largest * epsilon;

		if (diff <= temp)
			return true;

		return false;
	}


Here is a sample usage with DBL_EPSILON from <cfloat>:
1
2
3
4
5
#include <cmath>
#include <cfloat>
#include <iostream>
bool is_same = compare_float(std::pow(4.5, -3.5), 0.00517316346547085523109899, DBL_EPSILON);
std::cout << is_same << std::endl;


You can obtain machine epsilon from <cfloat> standard header, or if you wish you can compute one yourself (ie. to avoid header) with the following formula:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
	/**
	* Determinates epsilon specific to machine.
	* gives an upper bound on the relative error due to rounding in floating point arithmetic. 
	* https://en.wikipedia.org/wiki/Machine_epsilon
	*
	* @tparam FType		floating point type ie. float, double or long double
	*
	* @return			machine specific epsilon
	*/
	template<typename FType>
	FType machine_epsilon() noexcept
	{
		FType one = static_cast<FType>(1);
		FType half = static_cast<FType>(.5);
		FType epsilon = one;

		while ((one + half * epsilon) > one)
			epsilon = half * epsilon;

		return epsilon;
	}


example usage now looks like this:
1
2
3
4
5
#include <cmath>
#include <iostream>
const double epsilon = machine_epsilon<double>();
bool is_same = compare_float(std::pow(4.5, -3.5), 0.00517316346547085523109899, epsilon);
std::cout << is_same << std::endl;


This will work for for comparisons where arguments (compared floats) do not have to great precision

To make it work 100% we need yet another formula which will help us increase epsilon value (resulting is less accurate comparison):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
	/**
	* Shift decimal places of a value for specified amount of places.
	*
	* @param param	value to be shifted
	* @tparam FType	Floating point type
	* @param decimals	amount of decimal places to shift
	*					negative value shifts to the right
	*
	* @return		shifted value
	*/
	template<typename FType>
	FType shift_decimals(FType param, short decimals)
	{
		return param * static_cast<FType>(std::pow(10, decimals));
	}


Final example usage with shifted epsilon by ex: 10 decimal places now looks like this:

1
2
3
4
5
6
7
#include <cmath>
#include <iostream>
const short precision_shift = 10;
const double epsilon = machine_epsilon<double>();
const double d_epsilon = shift_decimals(epsilon, precision_shift);
bool is_same = compare_float(std::pow(4.5, -3.5), 0.00517316346547085523109899, d_epsilon);
std::cout << is_same << std::endl;


You can adjust machine epsilon as much as you need with shift_decimals function, result depends on how accurate you want your comparison to be.
Last edited on Oct 13, 2019 at 1:03pm
Oct 14, 2019 at 12:26pm
still i cant understand it. How i can do this without epsilon or etc.
theres any easy way to prevent this problem.
Code is not readable . Theres more easy way to do it.
Oct 14, 2019 at 12:55pm
still i cant understand it. How i can do this without epsilon or etc.

It's impossible to compare floating point types without epsilon, and without precision shift and expect to have correct result.

theres any easy way to prevent this problem.

no the is not an easy way, at least not as easy as you are expecting.

Code is not readable .

serriouslly? the code I posted is only about 20 lines, if you find that hard to read go ahead and implement your own more readable version.

I think your problem is that you don't understand what the code does despite detailed description, not that it's not readable. what portion of the code is not "readable"?

Theres more easy way to do it.

Let me know when you discover more easy way, I'm willing to import that into my library and replace the code with your solution.

You can start by reading how floating point works:
https://en.wikipedia.org/wiki/Floating-point_arithmetic

For your solution you're comparing multiple floats, so you can re-implement compare_float above to take variable number of template arguments so that single function call is used.

But I'm surely not going to tell you how to do that.
Last edited on Oct 14, 2019 at 1:04pm
Oct 14, 2019 at 1:23pm
I going to use stackoverflow beacuse your code adaptation in my project results 35 errors . And its want initalizer before noexpect but i cant understand it so i going to ask stackoverflow... If no one finds the answer i going to use world most inefficent way to make collisions this:
bool test;

if(tra_x == 0.4f)
if(test = true)
tra_x = false;
if(tra_z == 2.0f)
tra_x -=0.1f;
like thing.
probalary most cumbersome code i wrote ever.
Inefficent and problary my app its just now 15 kb after doing these cumbersome process it will be 500 mb collision code .

This teqnigue called Boolen Collisions most inefficent way to do it. None of modern games used it maybe in Dos days used by bad programmers.
Last edited on Oct 14, 2019 at 1:24pm
Oct 14, 2019 at 1:33pm
Dos programmers were better than you can imagine. You can't even do collision detection; they had to work in < 1 MB of memory and single or low double digit MHZ cpus with no floating point processor at all for most of that time. Yet they made rich games and powerful software. Doom. Heretic. Wolf3d. Elite+. Xwing and tie fighter. Just a small # of 3-d collision detection enabled amazing games that ran on dos (granted, those were post FPU dos but they ran on machines with single digit MB ram and < 60 MHZ cpus). Dos kinda sucked. The people that worked on it were extremely good.

if you want to compare simply, swap to integers. 64 bit ints have enough resolution to handle using them as if floats via shifting, for example 123.4567 can just be made 1234567 and multiply everything by 10000 when doing your pixels math.

Last edited on Oct 14, 2019 at 1:35pm
Oct 14, 2019 at 1:37pm
no problem, can you please share a link to stack overflow question? I'm really interested to see what other solutions might exist out there.

as for errors you mentioned, ti must be you're doing something wrong such as calling a function with noexcept keyword included?
Oct 14, 2019 at 1:51pm
<hided stackoverflow link beacuse pirivarcy)
my stackoverflow question without any answer
Last edited on Oct 14, 2019 at 1:59pm
Oct 14, 2019 at 1:58pm
So i coded these myself you can't expect world most perfect collision detection.
I asked everyone but no one gave me a algorithm that works.
Soo i go and i tried to make this.

But its not works correctly so i smashed another keyboard.
If someone has a basic collision detection (3d) algorithm please give me.

Oct 14, 2019 at 2:09pm
see, I told you float are special beasts to deal with ;)

You can download some open source game engine projects such as Unreal engine 4 and take a look how their collision detection works.

but know that the code wont be readable. in fact the most game engine code is a complete madness in terms of complexity when you start using it.

I recommend you to halt your work on a project. take a look at some opensource code bases, start slow, gather information etc.. . Implemening game engine isn't a job for beginners.
Oct 14, 2019 at 2:16pm
a basic 3-d algorithm...
just take the 3-d linear distance between points on your objects. I think we went over this before... nearest points of object A and B to each other: (A.x-B.x)*(A.x-B.x) +(A.y-B.y)*(A.y-B.y) + (A.z-B.z)*(A.z-B.z) < collisionvalue //whatever looks good on your scale in your code here. you can use the center of the objects and a radius, whatever, here. This is good enough until you start writing an engine for others to use or for a commercial product.
you can still use the adjusted integer idea I gave you above here if you need high resolution: I removed the sqrt for speed and simplicity so you don't have anything that HAS to be a floating point in that.

I can try to help but if the above is not trivial to you, then you are not ready for this project.
Last edited on Oct 14, 2019 at 2:21pm
Oct 14, 2019 at 2:29pm
i staying with world most buggy collision detection ever made. I just find alternative:An int will increase when the player moves. A little cumbersome to detect after a certain place in the code, but it works
its basic algorithm of it.
for example if player at 0.3 int will be 3 if player was on 2.0f other int value will be 20 and my collision detection system will be erude from tra_z value

Oct 14, 2019 at 2:54pm
Yes, if something is tile based, then I would suggest comparing integers (as if each integer is a different "tile").

If something is not-integer/tile based, then you must have some beginning boundary, and ending boundary. Never compare equality to the boundry itself, just ensure that the point you're testing is within the boundry, e.g. collision if left_side_of_boundary < point.x && point.x < right_side_of_boundary.
Last edited on Oct 14, 2019 at 2:55pm
Topic archived. No new replies allowed.