Introduction into Godot 3D Physics part 3

Introduction into Godot 3D Physics part 3

Articles, Blog , , 0 Comments


Hi all and welcome to part 3 and the last
of this mini series. I may do some follow ups on the subject in
the future but this part concludes our little cannon
game. Before we start I need to correct one small
thing from the last video. The math around gravity was wrong, distance travelled over time is accelation * time squared divided by 2. Seeing I forgot the divided by 2 halving the gravity worked around the issue. I’ve corrected the mistake in the github repository. The other noteworthy thing that was raised
by one of my viewers is something I take for granted
nowadays. You should never scale physics objects! The most efficient collision shape is the
sphere. Detecting a collision between two spheres
is super easy. You calculate the distance between the centers
of the two spheres. If this distance is less then the combined
radius’ of the spheres we’re colliding. If the sphere was scaled, especially with different scale factors for
each axis this wouldn’t work. Similar issue exists for the other collision
shapes that are all represented by mathmatical formulas that don’t react well when we’re trying to
apply scaling. Bottom line, do not scale your physics objects! Let’s go back to our project. We’re going to visualise which collisions
are contributing to our score. For that we need to know the location of the
object that resulted in our score increasing. We’ll be sending that information along with
our signal so we’re adding an at parameter. And then we add the global transforms origin when we emit this signal. I’m also getting rid of our print statement that we no longer need. With our new parameter we need to update our
UI script as well. We’ll be instantiating a scene at this location that will show our score so in order to identify that scene we need an export variable. We’ll be creating that scene in a minute and it will be a 2D scene! If we have a score scene we’re going to instantiate this scene when we score. Then we tell our new scene the score it will
be displaying. Now we need to position our scene and for
this we need to know the 2D location for our at
location. For this we get our viewport Then we get that viewports active camera And we call the cameras unproject position
function, weird name I know. We need to add our new scene to our UI scene which we should do before setting the position. Now we create a new scene and turn it into
a 2D scene. We’ll call our root node score. We add a label to actually show our score. We’ll give it a default value of 0 and make sure that is nicely centered on our
label. We’ll also assign our custom font. Next we’ll resize our label to be a nice square and we’re going to center it on our root node. We’ll quickly save the scene. And add a script to it. Now we add our set score function to populate our label with our score. Now we can go back to our UI scene and select the scene we just created so it
is instanced. Going back to our score scene we are going to add an animation player. We add a new animation to our animation player. Then we tick the auto play icon to make sure this animation plays when the scene is instantiated and added to our UI scene. We’ll change the animation to be 3 seconds
long. And zoom in on that a little. The first thing we’re going to do is add a call method track so we can call our cleanup
at the end. We often do this with a lifetime timer but seeing we’re going to be animating our scene
anyway we can also do this here. We right click at the end of our timeline
and insert a new key. Now we select our queue free method to free
our scene. Going back to our 2D editor with the label
selected we are going to create our first keyframe by clicking the key icon next to our position. Make sure your timeline is at the start. We are going to make this a bezier track so we get smooth transitions. We select the 1 second mark on our timeline and move our label into position. Then press the key icon again to create a
keyframe. At the 2 second mark we move it some more. And finally at the 3 second mark we give it
its final position. When we play this we see our score move along our path but its very rough. Lets give us some space to work with in the
timeline and click on the little curve icon to edit
our position curve. Now we can use our bezier handles to create a nice flowing movement line. Doing the same for our y position I do get
into trouble that I can’t scroll this interface very well. If someone could tell me if there is a trick
to this, please leave a comment. We can see thats better, not perfect but I don’t want to spend more time on this
in this video. Next we’re also going to add a scale track
into our scene. I’m starting at the just over half a second
mark where I want our shape to be scaled normally. And then at the start of our timeline I scale
it to 0 Then at the two second mark I want another
keyframe where the scale is still 1 And at the end of our timeline I want it scaled
back to 0. Now when we play we see our score pop into
existance, float up, and disappear. Now we want our block to be destructable. We already make it disappear when the block
is destroyed, we want some small blocks to take its place. We again create a new scene but this will
be a 3D scene. We’ll call the root node destructed blocks. We’ll create our first block just like before. We start with a rigidbody at the base. Then add a mesh instance with a cube mesh. We size this so 8 pieces fit into our original
shape. We also give it the material our original
block uses. We complete it with a matching collision shape. We move our first block into position. We’ll save our scene at this point but in this case I’m not saving our block into
a subscene. That felt like overkill. Now we duplicate our block and move the second block into position. We repeat this 6 more times. Now these blocks no longer play a part in
our scoring so we’re not going to assign our script to
them but we do need a script for our scene. In this script we’re creating a function that will copy the current velocity of the block being destructed to our 8 mini blocks. We can simply loop through our child elements
to apply these. Going back to our script on our destructable
object we’re going to add an export variable so we can identify our new scene. Here it is important that we can use different destructed scenes for different
objects. Now when we break our block we can instance
this new scene. We add this as a child scene of our current
scenes parent. We copy our objects global transform to our new scenes global transform to position
it. And we call our copy velocity function. To link it all up we’ll select our subscene. Now when we hit our front block with sufficient
force we can see we scored 100 points and we see
our block break into 8 smaller blocks. If we hit our second block we can see we also
break that one. As you can see I’ve duplicated our blocks
a few more times to create a more complex structure to knock
down. I want to add a different shape for us to
see how we can reuse what we’ve created so far
very quickly. So we start with a new scene where we change the root note to a rigid body. We call this triangle. As before we add a mesh instance. This time we’ll use a prism. Lets save our scene so we can add it to our main scene and check our size. I’m going to rotate it in our subscene as we’ll likely always use it in this orientation. That looks better but I want it to be less
tall. Yes 1 unit looks good. We assign the same material as we’ve used
for our blocks. Now we don’t have a triangle collision shape
so with our mesh instance selected this time
we’re going to use create trimesh collision sibling. This will create our collision shape for us and create a polygon based collision object
for it. Now why did we not use this before and why
don’t we do this all the time?! It’s so easy! Well it comes back to what we talked about
at the start. Mesh based collision shapes take far more
effort to test collisions against. If you can use spheres or boxes, use spheres or boxes each and every time. Interestingly enough our collision shape did not get the orientation copied so we needed to rotate it to match. Now we can add the same script we used for our blocks to our triangle scene. Going back to our main scene we can position our triangle properly, remember it needs to
fit snuggly. We’ll also create a second triangle by duplicating
the node. We want our triangles to break apart too. Before implementing this lets rename the script on our destructed blocks scene to just destructed.gd Always close scenes using a script before
renaming it. We create a new scene and rename its root node to destructed triangle We save our scene and attach our destructed
script to it. Now we repeat the steps we did for our blocks but now with triangles. We create our rigid body We add a mesh instance and add a shape to
it. Rotate it And use our mesh menu to create our sibling
collision shape. We then move it into position. And we duplicate it a couple of times and
positioning it. I’m just skipping this part. Let’s also set our material to all our mesh
instances. Yes I know I can set the material on the mesh
itself and seeing we’re reusing the mesh for each
instance that would be a single action. Habits don’t die easy, both are good options. Now we can hook up our destructed scene to
our triangle scene. We also need to ensure that our contact monitor
is turned on and we set our contact report to 10. And we hook up our body entered signal to
our existing method in our script so we react
to other objects hitting us. We got lucky on our first shot. It took awhile before everything caved in but our first triangle broke into parts in
the end. So far we’ve created objects that are fully controlled by our physics engine. We only control the initial speed of our cannon
ball. To round off we’re going to implement an explosive and in doing so we’ll look at a few new parts of the physics engine. We start with a new scene and change the type to a rigid body so that it does interact with the rest of the scene. We’ll add a mesh instance with a cube, this
will stand in for our explosive. With a material we turn it into a big red
cube. We also need a collision shape. Now we add our explosive into our scene. Again we need to place it precisely. Back in our subscene we’ll add a script to
our root node. The collision shape controls our rigid body
just like with our blocks. But we can’t use it to trigger our explosive. Remember our explosive will be resting on
the floor, so it will be colliding with the floor, things
can get pretty tricky. We’re going to trigger our explosive in a
different way. We are going to use an area node. An area node allows us to detect things going
on inside of the area but it doesn’t interact with anything. An area can be used to effect the gravity
settings within but we won’t cover that today. So we add an area node and call it our trigger
as this area will trigger the explosion. Then we add a collision shape that gives a
shape to our area. Again this doesn’t collide with anything. We resize our box so it is slightly larger
than our box and move it upwards so we don’t detect anything
underneath our box. Now we can hook up our body entered signal
so we can react on another object entering our area. We only want to explode once as we won’t remove
ourselves right away so we add a variable for this. If we weren’t triggered yet we’ll set our
variable to true. At the end for now we’ll queue free our object. When our box explodes this needs to have an
effect on all objects that are nearby. We’re going to implement that in the space
above but how do we find out which objects are close enough? Well we’re going to use another area! We call this Effect range We’ll add a sphere collision shape to it. Any object within this sphere when we explode
will be effected by our explosion. We don’t need to hook up any signals, Godot will detect when objects enter and leave
our area and remembers which objects are currently
within our areas collision shape. We can simply loop through the objects within
our area by calling get_overlapping_bodies on our area. Our explosive is also inside of its own area
so we ignore that. Else if our body is a rigidbody, and right
now it will be, we determine a direction vector by subtracting the bodies position from our own. We’ll define a variable with which we can
set the strength with which we effect our objects. Now we apply an impulse on each body using
the normalised direction vector and multiplying it by our
impulse strength. To keep things easy we just apply the impulse
to the center of our body. Applying an impulse on a physics body basically
applies a momentairy force to the object to push it
into that direction. If it is applied off center it will also result
in a rotation of the object. I’m being over careful here but we’ll see
eventually that we’ll hit our box and it will push all the
object around it outwards. In the final version I’ve also added a particle
effect for an explosion. We won’t handle that part here because its
an entirely different subject. You can find the source code for it on github. This is only the tip of the iceberg asfar
as the physics engine is concerned. Hopefully you have enjoyed this small introduction. I will be looking at kinematic bodies in the
near future and may do some advanced physics tutorials. Let me know what you guys would like to know
more about. If you’ve found this video useful please consider
liking the video. Until next time!

Leave a Reply

Your email address will not be published. Required fields are marked *