Hi, welcome to this new lesson. We are going to continue talking about behaviors that operate between classes. How do classes interact with one another? Especially what happens when we have large populations. At some point, we will start having challenges that have to do with the computational complexity of the problem. How many calculations can we really perform, especially if we are looking into real time computations, if we are actually not so interested in how long a certain computation will take, maybe that's something that we can avoid as a problem. But often it's important that we are aware of how much computational complexity is involved in a problem. So with that, let's jump into the code and start understanding what I mean by this, right? So, here we are. If you remember where we left off, we have this gradient rectangle class, which is basically a bouncing box. Let's just kind of bring down some of these variables. Maybe we wanted to have 20 of these. And we will actually turn on the background for every frame so that we can actually see them better, right? There we go. We also would like to. Let's just remove out of this in our class. We have a run function that operates as a dashboard, in a way, to control everything else. So let's just turn off the bounce_color so that we can actually see them more clearly as a single color. And we could even start with a color such as maybe white. Our beginning first color will be white. And you can leave on bounce_with_each_other. That's a function that we just covered. But actually, we will leave a bit of room here to actually write a function for line in range, right? So this is going to be a form of display function. Let me just make sure that we are kind of doing well with the white rectangles. Let's turn off for a moment the bounce with color. We can bring it back in a minute. But this function is new, and it's going to make it more clear if we're actually not necessarily seeing the bouncing with each other, but just isolating with the bouncing behavior of these rectangles, right? So let's define this line within range, right? So, line to others, and let's just call it line to others for now. And there we go. So let's think about this problem, right? How could we, based on what we've learned on this other calculation, right? We could even do something very similar to what we've done before here to find our adjacent unit up, right? Saying if our index is bigger than zero, the other entity up would be this one, right, the index above me, right? We could at this point draw a line, right? Let's just do a line that goes from self.vec_position.x, To, self position.y, right? Those are the first two coordinates. And in the other case, we could use the other, right? So, Let's do that, right? So this is a line, and let's just give it a color as well. So stroke(255), and then fill or strokeWeight. StrokeWeight, strokeWeight gives us the thickness of the line. So let's just start with something rather thick, and then we can calibrate it to something that it's more graphically pleasing. So let's understand what this line of code is saying. It's saying let's find our neighbor above us, which is the same thing that we did before, and let's draw a line between us and that entity. And only do this if you are the second entity in the list or beyond, right, until the last one. If you're wondering how come we're actually drawing all these lines without a loop at all is that you have to remember that we are within the class, right? We are writing behaviors from within the class and the class, each one of these instances of the class is being executed in a loop. So when we're writing these functions, we have to be considering that we're not trying to draw lines to all entities, but only entities with a particular relationship to us. In this case, being above us in the list, right? So let's just see if this line_to_others function is working as expected, right? Let's start. Let's just add the self. So here we go. We have these lines. If you see these lines, it's not a very pretty drawing, perhaps, but it does kind of explain the relationship that these units have with one another. This is very close to the way in which you could actually draw polylines, vertices, points, and then lines that connect them. We're getting a little bit into ideas of how data structures could be connected to geometry, but this is not exactly where I would like to go with this. This is kind of a very simple computation where we know our next neighbor is above us, right? But what if the situation changes and we want to be able to make lines to any neighbors around me that are perhaps within a certain range, then. Well, what we need to do is calculate our distance to each one of the entities and determine, are there within specific boundary condition? And this computation will start getting more expensive because every entity will have to loop through every other entity, right? So let's write it down and evaluate. Why is it more complex than what we've done here. So I'm going to actually copy paste this function because this function might be useful for you. You might want to leave it, For your own kind of research and your own kind of study of these functions. So we can change the name of this second function line to others in range. And it's going to use the same principle of this. >> Previous function, but let's change it. So I'm going to comment out the previous function and call this function, right? So this function is going to be executed. The other one we're commenting out because that was kind of a small demonstration, right? Hopefully at this point, you are familiar with the idea of how certain functions or methods, we call methods the functions that are within a class, right? How these methods could be left behind. If we don't ever call them within the class, they become archived in a way. They're basically not executed. But it's good sometimes to just keep methods that are useful or might kind of bring ideas for future behaviors, right? So what would make the range calculation work? Well, first of all, we need to do a loop, right? So we could say here for other in self., let's use the list. In the others list, right? So that's the loop, right? What are we looking for in the loop? If, other is not self, right? This is important because we do not want to calculate a distance to ourselves, right? And we can actually get rid of this statement now. Let's calculate the distance. The difference will be represented by the p vector sub. So we're going to do a subtraction between the vector of position, our vector of position. When I say our, I'm kind of speaking from within the class, right? I'm speaking as if I'm kind of when I'm writing within a class, I start thinking of I'm this rectangle, right? How do I kind of relate to another rectangle and how do I draw aligned to that other rectangle, right? So I'm going to do a subtraction between my position, that is, a self, right, .position, to an, oops. Let me just correct that, self.position to the other, .position, right? So we're calculating d, if you remember the vector and the subtraction between two vectors is the distance between them. It's very useful to understand the vector. Basically, if we calculate the magnitude of this subtraction vector, we will actually get distance between these two points. So the distance is the difference magnitude, and this is the way we actually ask for the magnitude of that vector, right. So with this distance value, we actually should have a way of evaluating if we want to draw a line. And we will be able to draw this line. Notice that this line actually right now is not just a line as we were doing before to our one neighbor up. But it's a line to, potentially, if we actually correct, this line is actually incorrect. But let's just, We're going to do a line to each entity that is within a particular range, a distance, right? So if the distance is smaller than, let's say something like 50, let's just start with a value, like a hard coded value, we will actually execute the line. So let's do this. So in this time, let's just do a slightly thinner line. And who is this line in between? This line is between self, so x, y, and other. But in this case, the other, we named the other based on the loop, right? So for other, the entity. Other is each entity as we're going through the list. So it's not the other_up that we had used before, but it's this entity within the loop. And that should be it. What we're trying to do here is any entity within 50 units of radius, we will draw a line to them, right? And this is one of the very traditional examples that is used in creative coding to understand how entities calculate proximity to one another. But because we have this for loop, and this is a class, we are actually doing a loop within a loop, right? It means that every class is being run as a loop. So we run through all the classes and each one of those classes will loop through every other class. So we're actually increasing, quite importantly, the amount of computational complexity of this problem, of this system, in a way. And if you start seeing your computer lag and starting to run slower, it's because we are indeed kind of doing quite a bit of computation. Or a lot more than what we used to do in this previous example, where we were just finding our neighbor. And that was basically we knew that our neighbor was the adjacent entity in the list. In this case, we're actually searching for them in a list. So let's see how this looks. So we are running into some indentation issues. Think that's what? So we have the for loop, the if statement, and only if. Let's see. So we can see some lines. If you pay attention, you can probably see them, but there are not too many of them, and they're very small. Let's just increase that value, right? Let's say that we want to do it over 200, right? So you can see now these lines appear and disappear, depending if an entity is within 200 pixels. So, yeah, this is great. This is actually working. This is kind of a system that is kind of quite used, kind of a graphic representation of lines between objects in proximity. A few things that you can do if you want to do the system slightly different you might also want to. Instead of doing the lines right, which I find sometimes the most obvious way of visualizing this, you might consider that you want to do something like, no, fill. Let's change to ellipseMode(CENTER), meaning that we could actually draw an ellipse with its center. And the ellipse that we want to draw here. Let's just copy the information that we've done for the rectangle, right? So this is the coordinate of the rectangle. We could actually say, hey, I want to do that. The size times 2. So whatever your size is supposed to be times two. And then for good measure, go back to no stroke, because we are starting with the stroke here. So what this would actually create, and if we actually create a few more of these entities. Let's go up to 50. We could actually see, and you'll see that this starts to lag, Due to the nested loops, right? Depending on the system that you're running, depending on your computer, we are actually running processing through Python, which is perhaps the most optimized version for real time graphics. You can actually have very performative real time graphics in other systems as well. But we certainly wanted to operate within the ecology of code of Python. Therefore, we've been running it here. We actually lost the lines, right? That maybe made this whole thing a little bit more visible. What else can we do here? I feel like the ellipse center, it's not really giving us the result we want, if you wanted this ellipse to be. Yeah, it's kind of working. We can actually, As you can see here, Turn off the draw for those rectangles, right? And then rely almost exclusively on this ellipse information. And again, playing with the line thickness, 0.5, you can actually go below the one pixel. So you could actually start getting this kind of thinner line representation. You've probably seen these kind of drawings before. It's something that is quite used within code structures, especially when you're learning how to do distance calculations. But just to wrap it up, this function, again, a lot of flexibility, but it comes at a computational cost. It comes at the computational cost of having a loop within a loop. And the bigger the number of entities that you might want to include here, you would see your performance running slower and slower, right? And there are ways of kind of optimizing these systems for them to run a lot smoother. We will potentially getting those into the next specialization. They have to do with kind of not really looping through all entities, but looping through entities that you might already know that are closer to you based on space partition, a way in which we could actually subdivide the space in a grid and already know that some entities are dynamically changing between sectors in a way. So there are clever ways in which we could actually make the computational complexity of a problem be resolved and still maintain good performance, right? But as we're learning, we are actually reaching the point where, for the first time, we're actually doing a loop that searches through all entities from within an entity like class. Therefore, the computational complexity is starting to be visible, right? So I'm going to leave this session here, and I'll see you in the next one, where we're going to start really kind of converting some of our old code. Especially our kind of ants and kind of grid systems into object-oriented interactions. So we're going to be wrapping it up here, and I'll see you in the next video.