Subtitles section Play video Print subtitles [BELL RINGS] Hello and welcome to chapter two of the Nature of Code, forces. So I want to start with this discussion by talking about Newton's laws of motion. So by no means is anything I'm going to do be a really accurate, robust physics simulation. But at a minimum, I want to examine what the basic laws of motion are, the basic principles behind how things move, and just make sure that the code I'm writing fits with that for the most part. So let's start with those laws of motion. Law number one. This is how it is often referred to most informally-- an object at rest stays at rest. However, a more accurate statement of this might be, an object at rest stays at rest and an object in motion stays in motion at a constant speed and direction unless acted upon by an unbalanced force. So that's a bit of a mouthful of stuff, but let's unpack that for a moment. Let's think about this in the context of our P5 canvas and the object being a circle that I'm drawing on that canvas. If this circle is going to obey Newton's first law, if it's not moving, there's no reason for it to start moving, or if it is moving at a particular velocity vector, there's no reason for that velocity vector to ever change unless acted upon by a force. The definition that I offered over here uses the term unbalanced force. So something that's very important about this concept of staying at rest or staying at a constant velocity is that it's not just whether the force is there or not, but whether the net force, the sum of all the forces in the environments, add up to something non-zero. For example, with my marker here, there's a force of gravity pulling it down, presumably towards the center of the earth, but there's also some other forces that I'm applying to it to keep it up, that are pushing it up. And so if I try my best to balance the force-- balance the force-- then it won't move at all. This diagram is another example of this. So all of these forces balance themselves out, and this object is at a state of equilibrium, meaning it won't start moving, or if it were, its velocity would remain constant. And the reason I'm harping on this so much is I really want to make sure when I go to write the next bits of code that I'm going to write, that the simulation obeys this law. But in order for it to obey this law in the first place, I have got to understand-- I'm using the term force all over the place. It's really important that I think I take a moment now to define what I mean by force. A force is a vector that causes an object with mass to accelerate. That is the technical definition that I am going to use for force. Here's the good news. Vector-- check. We've got that. I just did a whole section of videos about what is a vector, so we can understand force as a vector. Here's more good news for you. Accelerate-- check. I just did a video tutorial about how to apply acceleration in a P5 sketch. So if we can create a vector and somehow have that vector affect the object's acceleration, then we are implementing a force. And if the way that we implement the force in our code obeys this law, then we are golden. One thing here-- mass is not something that I have discussed, or used, or implemented as a property of any of the things I've done so far. So let's put a question mark there and return to that. Which leads me to Newton's second law, F equals M times A, or Force equals Mass times Acceleration. I can also describe this law as a restatement of the definition of force. Force is a vector that causes an object with mass to accelerate. We're turning back to the code for a moment. I have these two lines of code-- vel.add(this.acc), pos.add(this.vel). And in this example, everything starts with acceleration. I'm calculating an acceleration based on a vector that points from the object moving to the mouse itself. So if everything starts with acceleration, maybe I need to rethink the way that I'm describing this formula. And a different way that I could consider it is acceleration equals force divided by mass. The idea being that if I introduce some force-- like let's say there is a wind force with a magnitude and direction that I want to put into this environment. If I have that force, I could take that force, divide it by this object's mass, and that would become the object's acceleration, which would then affect its velocity, which would then affect its position. And this is the technique, the strategy by which everything I do is going to be built upon. I'm really ready to start implementing this in code. But before I do so, there's a few things I want to address. One is you might hear, when looking at how physics engines are built, the term integration. And this is actually one way of doing integration. This specific way is referred to as Euler integration. Why is it called integration? I'm getting into the weeds here into the math aspect of this, but it is important, and I think this will help you as you move forward and do more of this stuff when you see the lingo popping up here and there. In calculus, there's the concept of a derivative. And you might typically see this as written as like dx over dt, the change in x with the change in time. This is actually what velocity is doing. Velocity is dx dt. If x is position, velocity is the change in position over time. Acceleration is the change in velocity over time. So velocity can be thought of as the derivative of position, and acceleration can be thought of as the derivative of velocity. But I'm not going in that direction. I'm not starting with position, and then figuring out what's the velocity, and then figuring out what's the acceleration. I'm going in the other way. I'm starting with what's the acceleration, and then changing the velocity, and then taking the velocity and changing the position. So the other direction of doing the derivative is integration, the integral. So that's why this process is tied to calculus and the concept of integration. The big difference here is that calculus, being the study, in a way, of infinitesimally small time steps, these time steps are quite large. This algorithm is just being applied 30 times per second. But as I move my arm back and forth, are you seeing this animation at 30 frames per second? Maybe because you're watching a video, which is then recording me and playing it back at 30 frames a second. But the actual physical time space that I'm in is very continuous. The time step is infinitesimally small. And if I were doing an accurate calculation of a physics simulation, I would need to take that under consideration. Instead, I'm using a technique called Euler integration, which allows me to have fixed time steps, which are rather large, and it's wildly inaccurate. And I'll maybe back circle back to this as I look in future videos about other integration techniques. There's Berlet physics, and there's Runge Kutta integration. I probably didn't say that correctly. And so maybe I could circle back when we look at other physics libraries that might have slightly more robust methodologies underneath the hood. But the reason why I like this methodology is, number one, it works just fine. I just want my particles to spiral around the screen in pretty ways. And two, it's really fast and really easy to implement. So it has its advantages in terms of the kinds of examples and demonstrations that I want to show you. Also, I know there's so much more to this. Before you start typing your comments in the chat about the theory of relativity, and space-time continuum, and Planck time, and also "Plonk" time-- I don't even know how to say it-- my goal here is not to go in-depth into the physics of this, and I'm glad to include in this video's description other resources that do, but to take these ideas, these core classic concepts, and then work out a way to implement them in code. I should also mention there is Newton's third law, which is often stated as, for every action, there is an equal and opposite reaction. That's a little bit misleading, and I've written some thoughts about that here. Another way of stating that law is, forces always occur in pairs. The two forces are of equal strength but in opposite directions. So to be honest, this law is not so meaningful to me right now. Trust me, it's kind of important. But in terms of the simulation that I want to start with, I am not going to bother to simulate every possible reaction and opposite interaction of every force within the system. But this will come up again, and I will look at this law when, in a future video as part of this section, I look at gravitational attraction and how two bodies both attract each other, and those forces are of equal strength but in the opposite direction. To get started implementing Newton's second law in code, I want to build off of the example that I finished with in the previous section on vectors. So here, I have this mover object. It starts at a position 200, 200, and two functions are called, update() and show(). So if I run it, the acceleration is being calculated as a vector pointing towards the mouse. You could think of it as a force, a gravitational attraction force pulling into the mouse. It's not really that. Of course, it's not really that. It's just some pixels on a screen. But I'm not even using the formula for gravitational attraction. So I'm going to circle back to that and make some changes to this kind of idea later. But right now, what I want to do is change the way the internals of the mover object works because right now, the acceleration is being calculated right here in update(), and I don't want to do that. Instead, I want to write a function that's basically Newton's second law. So I want to write a function-- I'm going to change its name in a moment-- that implements this particular law. The law, again, is force equals mass times acceleration. But I've rewritten it to acceleration equals force divided by mass. Guess what? Let's just pretend for a moment that the world we live in, the world that I'm programming in, there's no concept of mass. In fact, everything in this entire universe has a mass of 1. So in that case, going back to this law of force equals mass, which is 1, 1 times acceleration is really just same as force equals acceleration or acceleration equals force. So these are the same concepts. Meaning, I could just say this.acc = force. There we go. This is the simplified version of Newton's second law in code. I'm going to change the name to applyForce(), the idea being that what I want to do is take a force that exists in the environment, not something calculated from within the object. That's going to be important later in some of the other videos I'll do. But right now, imagine a wind force external to the object, or a gravitational pull maybe pulling it down along the y-axis external to the object. For example, let gravity equal createVector(0, 1). I'm making a vector that points down, and then I want to say mover.applyForce(gravity). Let's run this code. Remember, this is the applyForce() function. It sets the acceleration equal to the force, and then that acceleration is added to velocity and that velocity is added to position. Ooh. [BUZZER] I forgot that I'm programming in a class, and in a class, I don't use the keyword function to define an instance method of that class, I just say applyForce(). Ugh. There we go. Look at that. There's that force of gravity pulling it down. This sketch is a little bit sad because the ball falls and it never comes back. So just for the purpose of demonstration, I'm going to add an artificial constraint to this particular sketch, where what I'm going to do is I'm going to look at this bottom edge, and if this circle reaches the bottom edge, I'm going to take its velocity and reverse it. Really, if I were doing a physics simulation, I would think about this as an object with a different mass, and what kind of forces are happening when it hits that object. But I'm going to just bypass all of that with a quick shortcut. I can come back and look at that a little later, maybe. But I'm going to bypass that with a quick shortcut of just inverting the velocity. And I'm going to do that by adding a function called edges to keep track of when the object hits an edge. So this is really your classic bouncing ball code, and I have another video that goes through this algorithm more specifically. But what I'm looking for is anytime that y position is at the bottom of the canvas or below-- because testing if it's equal to height is not going to do me any good. If it's not precisely equal, it could easily move past-- then I'm going to shove it back up to height because if it goes too far and it turns around, it could get stuck. So I'm going to make sure even if it goes past height, I set its position to height and then reverse its velocity. And let's take a look. Ooh, that didn't work. Why didn't it work? It's one thing to write a function. It's another thing to call it. So let's say mover.edges(). And there we are. So now this gravitational force is pulling the object down and it's bouncing up or down. Why is it going off to the right a little bit? It's going off to the right because I gave it an initial random velocity. Interestingly, you notice how it's slowing down and eventually kind of losing its bounce and stopping? In a weird sort of way, that's what I wanted to do. That feels realistic. But I can't see in the code why it's doing that because really, I'm reversing its velocity. There's nothing causing it. It should go all the way back up to the top, and then all the way back down there, then all the way back up to the top. And this, I think, is because of this Euler integration. I'm not looking at continuous time. And there's a lot of inaccuracies here. Not to mention the fact that I'm violating all of the principles of time and space by just resetting its position back to the height if it got below the height, so it's losing some time where it might regain its velocity moving back up. So there's all sorts of goofy stuff going on here. And these are the kinds of things that as a programmer, working with this in a creative context, ultimately, I'm going to need to do massaging and tweaking things to get it to feel right, whatever the types of application it is that I'm wanting to create. But right now, I just want to test if Newton's second law is at play. And I'm going to test that by doing this. Only if the mouse is pressed, apply this force of gravity, meaning the net force is currently 0 so the object is at rest. Now I am going to apply the force. I'm going to let go. Oh. [FAKE SOBS] [BELL DINGS] I'm applying gravity, but when I let go, I think the gravity should stop being applied because I'm no longer pressing the mouse. But the gravity still seems to be there. Why is that? Well, there's a flaw in the way that I programmed this. The flaw is that I'm setting the acceleration equal to force. If the force goes away, I don't set the acceleration back to 0, but I should. So one of the strange things about this Euler integration and algorithm is that while velocity and position are accumulating over time, acceleration is just a function, a calculation based on, at any given moment in time, what are the forces in the environment? So at any given time, we should start with an acceleration of 0. And there only is an acceleration if there is a non-0 force. So there's a variety of ways that I could handle this. I'm going to just, I think, for simplicity, say this.acc.set(0, 0). So this is me just clearing the force out at the end of every animation cycle. So now, let's see if Newton's second law-- sorry, first law-- is really at play, and the second one. Oops. Cannot read properties set of undefined because I haven't given acceleration of value until I've applied the force, so this is just a flaw in how I've written the constructor. I also need to say, initialize a starting acceleration of 0. Now here we go. The object is staying at rest. There's no force. I click the mouse. Whoop. I let go of the mouse and it just flew off. Let's make the gravity less strong. I'm going to change this to 0.1. I'm holding down the mouse. There's gravity. I let go. The gravity is gone. The object keeps its constant velocity because there's no force acting on it. Let's try also now adding a second force into the environment. So there's one force pointing straight down called gravity. Let's add another force called wind and point it to the right. Let's get rid of the if (mouseIsPressed). I'll come back to that in a little bit. So now I've got gravity pointing down and wind pointing to the right. Of course, I could have just made one force with this as the x component and this as the y component. But I'm demonstrating an idea that as you start to build these kinds of simulations, there might be a variety of forces that are at play or not at play, based on any number of factors, and you can now separate those out into different vectors and individually apply them to your object. Let's run this sketch and see what happens. Wait a second. This I anticipated-- this error. Why is gravity not being applied? I only see wind. Let's change the order here. Let's put wind-- I don't know. Let's move the code around a little bit. Let's declare wind and gravity there, but now apply them like this. I don't know. Is that going to do anything? Wait. Now, only gravity is being applied, but not the wind. Go back into the mover. What's wrong? this.acc = force. So stepping through the code, mover.applyForce(wind). this.acc = wind. move.applyForce(gravity). this.acc = gravity. I just overwrote the wind. The wind is ignored because I'd take gravity and put it into acceleration. As I was diagramming this and describing it, I think a couple of times, I used this term net force, or the sum of all forces, or this idea of force accumulation. Meaning the object's acceleration is a result of the sum of all of the forces in its environment at any given time. Wind and gravity both act on the object, and both get added into the acceleration. So this applyForce() function shouldn't actually set acceleration equal to force, but rather it should call add. this.acc.add(force). I can call applyForce() as many times as I want and add up all the forces into the acceleration. There we go. The visual result of that isn't super interesting. Let's make it a little more interesting by saying-- and I'll make the gravity a little stronger. So now the wind will only be applied if I click the mouse, but gravity will always be applied. Let's see if this works. There's the ball bouncing. And now I'm going to click the mouse and the wind-- oh. Let's add some more edges. So now I've added a check for the right and left edges, and make sure the x slides back onto the edge, and the velocity is reversed. We have probably more elegant, and efficient, and shorter way to write this, but I'm just putting it in there to get it to work. Let's see how the forces are going. Gravity. And now I'm going to click the mouse, and wind is happening. You can see that. The wind is pushing it in that direction. But let's let go of the mouse and now the wind is no longer there and it's bouncing back and forth. The x velocity is constant now because there's no x component to the net force. But I could add the wind back in and we can see now it's pushing it to the side. I could also just increase the relative strength of these forces, just to see what that looks like. And we can see that here. And we see I already have a pretty interesting and dynamic simulation going. This is a small detail and not super important, in terms of what I'm doing, but it would be nice to actually have the ball reverse its course when the edge of the circle hits the edge of the canvas, rather than the center of the circle. So in that sense, I could add another variable for r to keep track of the object's radius. So I'm going to say this.r = 16, and then draw the ellipsis, this.r * 2, and then use this.r to determine where the edge is. Let me have it move a little slower so this is hopefully a little more visible. Ooh. Whoa. I forgot something. I've got to set it back to this.r. There we go. So that's a little bit more realistic in terms of where it's actually bouncing in terms of hitting the edge. So this is a good stopping point for this example, I think there's of twists you could do on this. First of all, I've just hardcoded numbers here for wind and gravity. There might be other ways you think about calculating those. For example, you could actually pull from a weather API and get the actual wind and have that affect this object. Or you could use Perlin noise. Maybe these vectors are changing over time for some other reason, or there's more than two forces. So many ways you could go in this direction, but this is a bit of a foundation, upon which you could build a simple interactive simulation. There's a couple of different things that I want to do with this example, which I'll do in separate videos. Number one is there's no concept of mass here. So what would it mean if I added to the mover object a mass property, and how would I use that mass value and actually bring that back into the true Newton's second law, force equals mass times acceleration? So I want to bring back mass. Bring back mass. Then I also want to investigate other forces that I can look up a real-world formula for and see if I can implement those. And the first one I'll do is friction. For example, there's this thing happening where the ball comes to a resting point, but then it just rolls back and forth. Could I simulate the friction of it against the edge and have it slow down and reach a stopping point? So the next video, I'll start with math, and then I'll look at friction, and keep going from there, finishing up with looking at the real formula for gravitational attraction and how I might implement that in code. So maybe I'll see you, maybe I won't, and go on with your day. May the force be with you. I said it. I said it. I said it. Goodbye. [MUSIC PLAYING]
B1 acceleration velocity gravity object wind vector 2.1 Simulating Forces: Gravity and Wind - The Nature of Code 1 0 林宜悉 posted on 2020/03/28 More Share Save Report Video vocabulary