Revisiting Collision Detection

Suppose we want to know the collision status between each pair of items in our game:

Our game objectsCheck them all aginst each other!

The (naïve but straightforward) approach we could use is a nested for loop. Simply compare each object to every other object:

for(int i = 0; i < 10; ++i)
{
	for(int j = (i+1); j < 10; ++j)
	{
		//Given the indices of two game objects,
		//this function determines if they're colliding
		TestCollision(i, j);
	}
}

QUESTION

Why would we assign the value (i+1) to our inner loop index, j?)


We assume that there is a function we could call, which

  • takes in a pair of game object indices, which are just integers
  • returns a bool (the result of the collision check):
//Function prototype for TestCollision
bool TestCollision(int gameObjectIndex1, int gameObjectIndex2);

When we wrote our loop previously, we didn’t store away the value returned from the function. But what if we wanted store ALL of the results of our collision detection test, into variables?


Storing and accessing LOTS of data

If we were NOT going to use a loop to do our collision detection, our code would look something like this:

//We're evaluating the same code as our loop, just manually
TestCollision(0 , 1);
TestCollision(0 , 2);
TestCollision(0 , 3);
TestCollision(0 , 4);
TestCollision(0 , 5);
TestCollision(0 , 6);
.
.
.

So, if we want to store off the results of these calls, what might that look like?

bool isColliding_0_1 = TestCollision(0 , 1);
bool isColliding_0_2 = TestCollision(0 , 2);
bool isColliding_0_3 = TestCollision(0 , 3);

Oh, HECK no. This is a really bad idea. It would be even worse if we tried it in a loop:

for(int i = 0; i < 10; ++i)
{
	for(int j = (i+1); j < 10; ++j)
	{
		bool result = TestCollision(i, j);
		
		if(i == 0)
		{
			if(j == 1) { isColliding_0_1 = result; }
			else if(j == 2) { isColliding_0_2 = result; }
			else if(j == 3) { isColliding_0_3 = result; }
			.
			.
			.
		}
		else if(i == 1)
		{
			if(j == 2) { isColliding_1_2 = result; }
			else if(j == 3) { isColliding_1_3 = result; }
			else if(j == 4) { isColliding_1_4 = result; }
			.
			.
			.
		}
	}
}

Arrays

Definition: Scalar vs Aggregate

Scalar Variables

hold a single value

Aggregate Variables

can hold a collection of values

So far, we’ve only dealt with scalar variables, like integers, floats, and bools:

//Variable x represents a single memory location
//with the size of a signed integer (usually 4 bytes)
//If we read the data (binary 0s and 1s) from this 
//memory location, we know how to interpret it 
 
int x = 47;
Variablex
Memory Address0x006ffbb4
Value47

An array is a data structure that allows us to store a collection of data. An individual piece of data in the array is called an element.

To create an array in C, we must specify the type of the array (is this an integer array? A float array?). We must also specify the size of the array (the number of elements it will contain):

//This is how we declare an integer array
//This array has 5 integers in it
int myArray[5];
 
//We can make other kinds of arrays too:
bool isAnImposter[8]; //bool array of 8 elements
char theAlphabet[26]; //char array of 26 elements
float distanceToShrine[7]; // float array of 7 elements

Here’s what our integer array looks like:

myArray

QUESTION

We just created an integer array called myArray above. Right after this array is created, what is the value of each element?

Now we’ve got some arrays! Uh… how do we assign values to an array? And how do we access them later?

Well, we know the array’s name/identifier, same as if we’d made a single integer variable! But to access individual elements, we add a pair of square brackets on the end, with the index of the element:

//This code sets the first element of the array myArray to the value of 847
myArray[0] = 847;

Each individual element is anonymous; it doesn’t have a name. So, if we wanted to set the elements in our integer array to be multiples of 100, it’d look like this:

//This is how we declare an integer array
//This array has 5 integers in it
int myArray[5];
 
//Set the elements of the array
myArray[0] = 100; //first element, index 0
myArray[1] = 200; //second element, index 1
myArray[2] = 300;
myArray[3] = 400;
myArray[4] = 500;

We could also do this in a loop, to make it easier!

Arrays in Loops

Finish the shell of the program below, to achieve the ouput from the code block above. ONLY FILL IN THE BLANKS (do not otherwise edit the program or add more lines).

int myArray[5];
for(int i = 0; i < 5; ++i)
{
  /*PUT CODE HERE*/ = /*PUT CODE HERE*/;
}

Loops and arrays were made for each other! We can now easily write code to not only store large swaths of data, but also access/modify that data!

Warning! Boundary Checking!

Reading/Writing outside the bounds of an array is LEGAL, but completely undefined! This is a very common mistake/bug made by programers across all experience levels. But it is a particularly galling bug for new programmers. The debugger is your best friend for finding and fixing these errors.

Errors caused by out-of-bound array indexing can be tricky because the behavior really IS undefined! Your code could crash, produce an infinite loop, or present results that make no sense in the context of your program.

Exercise: Out of Bounds!

Copy the code below into Visual Studio, compile it, and run it. Observe what happens. If the program crashes with an error, what is the value of i at the time of the crash? Change the condition in the first loop to i < 1000. Does the program behave differently?

int main(void)
{    
	//Set the values in our new array
	int smallArray[10];
	for (int i = 0; i < 10; ++i)
    {
		smallArray[i] = i;
    }
    
	//Out of bounds!
    for (int i = 0; i < 1000; ++i)
    {
		printf("Value in smallArray:%d\n", smallArray[i]);
    }
    return 0;
}

Exercise

The program below loops through numbers 0 to 150, inclusive. Create an array which stores an integer value for each Gen1/Kanto Pokemon. The integer value of a Pokemon will be used to determine if it is one of your favorites. Set your three favorites after creating the array (1 being most favorite, 3 being third favorite). Every other integer value in the array should be 0.

ONLY FILL IN THE BLANKS (do not otherwise edit the program or add more lines). If you don’t remember the Gen1/Kanto Pokemon, click here

/*
	Example output:
	Pokemon 5 is favorite #: 2  
	Pokemon 93 is favorite #: 3  
	Pokemon 149 is favorite #: 1
*/
 
int main(void)
{
    /*PUT CODE HERE*/ = { /*PUT CODE HERE*/ };
    /*PUT CODE HERE(favorite Pokemon 1)*/ = 1;
    /*PUT CODE HERE(favorite Pokemon 2)*/ = 2;
    /*PUT CODE HERE(favorite Pokemon 3)*/ = 3;
    
    for (int i = 0; i < 151; ++i)
    {
        if (/*PUT CODE HERE*/)
        {
            printf("Pokemon %d is favorite #: %d\n", /*PUT CODE HERE*/, /*PUT CODE HERE*/);
        }
    }
    return 0;
}
 

Copying arrays!

Arrays are special, and cannot be assigned to each other like normal variables. For example:

//This works
int x, y;
x = 5;
y = 6;
x = y; //x is now 6
 
//Create an array, set its values
int myNumbers[10];
for(int i = 0; i < 10; ++i)
{
  myNumbers[i] = 9000 + i;
}
 
//Nope, this does NOT work
int myOtherNumbers[10];
myNumbers = myOtherNumbers;

Exercise

For the Pokemon program we made previously, use the watch window and the memory window to look at the array, and find your three favorite Pokemon. At what memory locations are your three favorites located?

We can actually drag a variable from the watch window over to the memory window; the memory window will jump to the location of your variable, in memory:

Collision Detection

We could do something like this:

bool object0Collisions[10];
bool object1Collisions[10];
bool object2Collisions[10];
bool object3Collisions[10];
.
.
.

And that wouldn’t be a terrible strategy… but there’s something we can do here that’s better. But we’ll save that for next time!