Hi, welcome to this new video. We're continuing our work in project 1, which is a particle system. In this video, we're going to be working on adding a trail system to our particles. So what I mean by a trail is that at certain point, we might want to see the movement of a particle and basically have a sense of the history of particle position. So trails, it's kind of a visual effect that allows us to see maybe the past points of each one of these particles over time. We could do that for every frame, and that would be an incredible amount of data where every particle is keeping track of every point it's been. But often what we're going to do is this trail is just keep maybe the last 20 or store like maybe 20 positions. So that gives us some indication, like a ghosting effect of where the particle has been. How are we going to do that? Is we're going to be dropping basically making a copy of the position. As we're moving along, we're going to creating a copy of the position, which is a vector, that's going to be saving an internal list within the particle. So we're going to be storing those previous positions, if you want, history of positions, and then eventually, let's say, if we want our trail to be of 10 iterations or 10 particles or 10 trail points, if you want. We can actually remove the last element of that list, and that would actually look like the last 20 points or the last 10 points are the last points that are showing the past position of the particle. If that's not making too much sense, we can actually look in code. One important thing is that we don't have to also store the position every frame. We can do it every other frame or we can do it every five frames. So as you can see in the example code in the right, we're using something called the frame count and the module operator with a five saying, every five frame. So if the remainder of this operation is zero, at that point, let's create a copy of the particles position and add it to our trail so that we can actually maybe create a gap or sample every five frames the position of a particle. So we'll create this ghosting effect or a sense of where particle has been. So let's write it in processing and understand a bit further how this would work. The first thing I would like to do here, if you remember, I'm continuing with the script that we did last week. We have this particle system going from the mouse. I'm going to restore this part of the code. This time, bring it back to our setup. So I just want to have a bit of code that initiates the particles from the position of the middle of the screen, not from the mouse. Because what I like doing when I'm learning a particular subject is isolating the variables that we want to look at. Let's say we want to create something like 50 articles, and all of them will start from the middle of the screen, not too many. They're dying pretty quickly. So let's just also make sure that we in our lifespan, let's give them enough lifespan, maybe 300. So that we can actually see what they're doing. So we have 50 particles, they have a reasonable lifespan, so it's a little bit going back to what we had. But we now have a clear canvas to work on the trails. What will be the trail? The trail will be another kind of variable that we're going to add to this particles. So let's do self.trail, and it's going to be an empty list. This is going to be an empty list, and we're going to start populating this list with copies of the position. So we can write a new function here. So the definition of update trail is going to be a function for updating the trail or basically constructing the trail in a way. We could do it every frame, but let's just do this short line of code that would allow us to do it every handful of frame. So if the frame count modular operator. Meaning, the remainder between eight and the frame count equals zero, eight is an arbitrary number. I'm saying every eight frames. But if you want to do it every other frame, you would put a two. Every five frames, you would do a five. Let's say every five frames, we're going to be storing in the trail so self.trail which is a list. Self.trail.append. What do we want to append? We want to add a copy of our position, so self.position.copy. If we just put position, it will basically store the actual position so that would basically move. That trial will be moving with the position of the particle. We don't want a reference to the position we want a copy, which is a completely new piece of information that is frozen in time when that position was actually saved. At this point, if we keep doing this, this list will go forever, so we could run out of memory because the trails would be too long. In some cases, we might want to allow the program to go slower, and if we're recording frames and the computation starts getting slow, we might still be able to restore its full frame by doing an animation of it. You can decide if you want your animation to run real time, you can keep it light. But if you don't care for it to run slow and you want to do say a beautiful animation that might take some time to compute, by all means, you can leave more trials on and you can create some beautiful drawings in that way. If we're going to in this case, limit the size of this trial, if the length of the trail, it's bigger than, let's do 15 as an arbitrary number that represents how long do we want the trail to be. Again, this could be a variable that you create for the particle so you have more control over the particle's trail length. Self.trail. We're going to pop zero. Zero here is the index. If you remember the pop function, the pop function is going to be a way of extracting or removing from this list an index based on an index. We're going to pop the first entry. If you think about it, as we keep adding elements to the list, the last one would be the most recent position of the particle. The first entry of the least is the oldest position of the particle. If we pop zero, meaning at the beginning of the list, that would be the oldest position we have. We're going to remain with the closest, let's say, 15 points in this case that have been recorded for the particle. Update trail. There we go. I think we are trying to make sure that that function is written well. We have that function. We could execute that function. We can put it all the way here. Update trail. But you can see here, we're actually creating the trails. If we actually re-run this, it's running, but we cannot see anything. There's no change to our system. That's because we created data, but we haven't visualized that data. We created data, which is the history of the particle in the form of a trail. But if you can go to our Display function, which controls the graphics. Let's create a bit of room here. We could do it as a function. Let's do it as a function. You seen some of our examples, we're going to maybe write a longer function for display that includes the trails, but you could separate it, again modularity. It's always better. Display_trails. What we want to do, let's just create a four loop for t in self.trails. T is going to be one of the trail points, and we could say we want an ellipse, that is t.x. We know this is a vector. Use a copy of position, t.y. It has an X and Y, and let's just give it a very small size. To differentiate it from the particle itself, I'm going to say no stroke, and feel it's going to be red. That's all good. We have a new function that displays the trails. It goes through how long the trails is. It's like it might have one entity up to 15, and it's going to display them as also ellipses that are in this case, red. Let's just copy the name of this function, and just after the display, we're going to display the trails. The good thing about this kind of doing it as a function is that if you don't want the trails, you can always comment it off. You can always turn on and off, some of these functions that might not work. Let's see what are the errors that we have right now. We were running into an error, and I think it's just that we need to make sure that we're spelling things correctly. I think our variable trails have been interchangingly using trails, and trail. Let's just keep consistent. But most importantly, here, is self.trail is our variable. You can check here self.trail and self.trail here. We're still running into an error. Because we changed the name of the function, so probably we have to change the name of the function here too. Let's see it now. There we go. You can see now that these particles have these kind of red trails. Let's just comment out for a moment. They compute forces, and let's give them a little bit of higher lifespan. We can see them a bit better. Now, you can see the lines. They look like lines, but there are a series of points. What if you want these kind of trails to be a bit longer or more scattered? Well, you can go into this frame count, and this variable here, is five, which is, again, hard coded. You could give it a trails gap like a name. Let's just do something like 10, and see what happens. We're not changing the number of trail points, but you see that the trail points now are a bit more scattered from each other. We have a total number of 15 points. This is because we have a 15 here, but we could say the number to be five. We want to make short trails or you see we have that effect. But maybe you want to have maybe something like 40, a much larger number and maybe the distance again, maybe tighter. You can see we could have much longer trails. All of this comes with the cost of adding more data, more memory to our program, and you know more computation to what we're doing. But, it's good to know what are the kind of components that we're adding to the mix here. I'm going to leave it here with a number such as 15 and eight, which is what I've calibrated to our intention. We have a new display trail function. One final thing that you might want to do, and I think some of our examples show how to do, is that, instead of drawing the dots, you might want to draw a line. I invite you to really try to do that function yourself before looking at the examples and how we've written that for you. But the way you would do that, is that, starting from the second point in the trail, you can always draw a line between the second point and the previous point. The first point you wouldn't be able to do it because in the list, you wouldn't have a previous point. You would run into an error. But from index 1, you can always write a line between the trail point index 1 to index 0, from index 2 to index 1, and so forth. You could do in this loop, you could do an if-statement that would exclude the first point, and then basically, instead of an ellipse, you would draw a line between a trail point and another trail point. Again, that's an invitation to explore yourself or look at the examples that we have provided. But otherwise, I'll see you in the next video.