Skip to content

Godot Physics Engine tutorial created for BUK Påskecamp Online 2020

License

Notifications You must be signed in to change notification settings

Ghostbird/BUKpc20-koding-physics

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Godot Physics Engine tutorial

In this tutorial you're going to learn how to make use of the Godot physics engine to build a game while writing very little code. The physics engine is the part of Godot that makes a certain kind of objects behave according to the rules of physics in the game world. This enables us to make things fall down, and touch each other, without writing any code.

Requirements

For this tutorial you need a computer with the Godot Engine installed. You can use the Godot Engine on Steam, or you can download it directly from the Godot website.

Getting started

Next you're going to have to download this project's start point. Extract the ZIP somewhere on you computer.

Now open Godot and select Import. import instructions

Select the path where you extracted the ZIP, click the project.godot, then select Import & Edit.

Rigid body physics

Rigid body physics is a name for the behaviour that you would expect a hard, solid object to have in the real world. In the project, a few rigid bodies have already been prepared.

In the left bottom part of the Godot window is the FileSystem tab. Open the folder objects and open block-square.tscn.

In the Scene tab on the left you can now see that a square block object is a RigidBody2D that has a Sprite and a CollisionShape2D. The sprite is the picture that makes the rigid body visible. The collision shape has been made invisible. Click the closed eye icon to the right of CollisionShape2D to show the blue collision shape overlay.

As you can see the collision shape closely matches the shape of the picture. This makes the behaviour as realistic as possible. Click the now opened eye icon again to hide the collision shape.

In the Scene tab, click RigidBody2D. Now to the right at the Inspector tab. You can see that the Mass of the square block is set to 1.

Now in the Filesystem tab open the block_horizontal.tscn. You'll see that it has the same structure as the square block, but a different picture and shape. In fact it is the size of two square blocks. Click RigidBody2D here, and look at the Mass. It has been set to 2. This means that it will behave exactly twice as heavy as the square block.

To us this makes perfect sense, but this is one step that you must not forget when you create your own rigid bodies. Godot cannot know that you want this object to be twice as heavy as the other, simply because it is twice as big. It could very well be that one was made of stone and the other of wood.

Add a ball

Now you'll create your own rigid body. In the top left corner of Godot, click Scene » New Scene. In the new scene on the left side, click + Other Node. Select RigidBody2D and click Create.

Next click the + icon to add a child node or press CtrlA. Select Sprite and click Create.

In the Inspector tab to the left, you'll see that Texture is [empty]. In the bottom-left FileSystem tab, open the assets folder and click and drag ball.png onto the [empty] value after Texture. Now you should see a huge ball in the central scene view.

Grab one of the corners of the ball image and drag it while holding Shift, to resize it to a square that is two by two grid tiles in size. Then reposition the sprite so the centre cross is on the intersection of the coloured axes. Ball scaled and positioned

Now you have the image of the ball in place. However, there's still a yellow alert icon after the RigidBody2D in the Scene tab. That is because you have specified how the object looks, but not yet how it is shaped.

Click the RigidBody2D in the Scene tab. Add a child node. Select CollisionShape2D and click Create. Look at the Inspector tab to the right. You'll see that the Shape is [empty]. Click it and select New CircleShape2D. You'll see a small blue dot in the centre of your ball. Grab the orange point and drag it so the blue area exactly covers the picture of the ball.

Now you don't need to see the collision area any more, so in the Scene tab, click the icon after CollisionShape2D to hide the blue overlay.

Finally save this file in the objects folder as ball.tscn.

The first level

Now that you have prepared the necessary objects, you can build a first level just to play around in.

Open levels/001.tscn in the FileSystem tab. This is a level with just one base Node2D that has been named World.

From the Filesystem tab objects folder, drag a couple of blocks and balls into the 2D view. Remember to place them within the thin blue outline that shows the camera viewport. Otherwise they will be off-screen.

Now click Play Scene in the top right part of the window, or press F6 to start the current level.

If everything went alright, you'll see the placed objects drop out of view. This shows that gravity works.

Of course, this is rather boring.

Static body physics

Since you want something to build on, you need to learn a second type of physics engine body. The static body has the same collision behaviour as the rigid body, but it cannot move. This is the ideal type of object to use for the fixed parts of your world.

Click the World in the Scene tab and add a StaticBody2D. Rename this StaticBody2D to Ground just to easily identify it. Drag the Ground down to the bottom of the camera viewport. It doesn't matter that it won't exactly snap to that line.

Add a CollisionShape2D to the Ground. Then in the Inspector tab, click the Shape [empty] and select New RectangleShape2D. Grab a corner the blue square that has appeared in the view and drag to widen it so that the rectangle covers at least the bottom of the camera viewport.

Now press Play Scene again and see what happens. If everything went well, the falling objects should have stopped just above the bottom of the screen.

However, it is a bit weird that the ground is essentially invisible. To remedy that, click the Ground in the Scene tab and add a ColorRect. It should appear as a white square below the ground line in the 2D view. Move and resize it so it covers the blue rectangle that indicates the collision shape. For some added flair, click the Color property in the Inspector tab and pick a colour of your choice.

When you now Play Scene again, you should see your rigid bodies fall down onto the coloured ground.

Building time

Drag objects into the 2D view and build something by stacking them. You should enable smart snapping to allow the blocks to snap correctly to the half-way points in the grid. Pay attention that when have placed a block, you click the background to deselect it before you drag the next object in. Otherwise you might attach objects to each other, and that can give unexpected behaviour.

Practical physics

If you place a ball in the air, and you can have it destroy you building as it falls down. You might notice that the ball is not doing much damage. This is because the ball is fairly light compared to the blocks. However, we can change the mass of this specific ball in the level. Click the ball, then in the Inspector tab change the Mass to 10. Now when the ball falls down on your building, you can see that it shakes it quite a bit more.

Mass is not the only physical property that we can edit in the Godot physics engine. Many more properties that you might recognise from physics at school are editable.

Place the ball a distance away to the left of your building, a short distance above the ground. If you lack space, you can drag select the entire building and move it entirely to the right to free up some space.

Now click the ball and in the Inspector tab scroll down a little, you'll see the header Angular which has a velocity value. Change it to 1000 and hit Play Scene to see what happens.

If all went well, you've just created a heavy ball that is spinning at high speed, and will start slipping and rolling towards your building once it contacts the floor. You'll notice that it is slowed by to contact with the floor and the building blocks.

It becomes even funnier when you look at the Linear velocity and set its x to 1000. This should turn your ball into a projectile that rams your building at high speed and rotation.

Of course the ball is not the only thing with these properties. Every building block can have its values changed too. What happens when you change the Gravity Scale on a foundation block of your building to -10?

Other interesting properties are the linear and angular Damp which stands for damping. This means how much of its velocity is lost, gradually, or through collisions. The standard value of -1 is a special value and uses the standard physics engine value. If you give the ball an angular velocity and set its damping to 0, it will hardly ever stop turning, even when it rolls into something.

Interaction

This of course is all fun, but before it becomes a real game you need some form of interaction. Therefore, we must write some code. Luckily, the code to make this into a fun sandbox is very simple.

Open the objects/ball.tscn. Click the RigidBody2D, click Attach script button and click Create. Then select everything and replace it with this piece of code:

extends RigidBody2D

export var elastic_strength = 10;

func _physics_process(delta):
    # If the user holds down the left mouse button
    if (Input.is_mouse_button_pressed(BUTTON_LEFT)):
        # Apply elastic band towards the current mouse position
        self.applied_force = (get_global_mouse_position() - self.position) * elastic_strength;
    else:
        # Remove elastic band
        self.applied_force = Vector2(0,0)

Now go back to the 2D view of the level. Run Scene and hold down the left mouse button. If everything went well, all balls in the level should gravitate towards your mouse cursor, as long as you hold the button down. The further they are from your mouse, the more they are attracted, as if connected by a rubber band.

One interesting thing is that in the code above, we export the var elastic_strength. This means that you can edit it in the editor, just as we could with the other physics values.

If you did not already have multiple balls in the level, add one. Then change on of the balls' elastic_strength to 5. Play Scene once more, and see how they behave.

Goals

Now that you have a sandbox game, you might want to add a way to win a level. To do that we're going to program a simple requirement.

Click Scene, New Scene and select 2D Scene as root node. Rename the Node2D to Base. Then save this scene in a new folder requirements and name it base.tscn.

filesystem structure after the save

Now, click the button to attach a script, then click Create. Replace the contents of the script with:

extends Node2D

export(String) var next_level;

var passed = false;

func _process(delta):
    # Requirements passed and there is a next level
    if (passed and next_level != null):
        # Go to the next level
        get_tree().change_scene("res://levels/" + next_level + ".tscn")

Congratulations, you have just created an impossible requirement. You'll never pass this requirement. And therefore you'll never reach the next level. It might seem kind of stupid, but we will use this as the base for more complex requirements.

A real requirement

Click Scene, New Scene and select 2D Scene as root node. Rename the Node2D to OffScreen. Then save this scene in a new folder requirements and name it off-screen.tscn.

Click the OffScreen and attach a new script. Now in the window, don't click Create right away. Instead click the folder icon after Inherits: Node2D. Then select requirements/base.tscn. The Inherits: should now be "res://requirements/base.gd". Click Create. Remove everything below the first line of the script. It should look like this:

extends "res://requirements/base.gd"

This script now has all the functionality of the Base requirement, even though you don't see it.

Click the OffScreen in the Scene tab, and attach a new child node. Select VisibilityNotifier2D.

Click the VisibilityNotifier2D in the Scene tab and now look to the right side of the window. Besides the Inspector tab, there is the Node tab.

Click the Node tab. Now double-click screen_exited(). Then click Connect. You're now back in the script of the OffScreen but a few lines have been added. It should look like this:

extends "res://requirements/base.gd"

func _on_VisibilityNotifier2D_screen_exited():
    pass # Replace with function body.

The function _on_VisibilityNotifier2D_screen_exited is only activated when this object leaves the screen. That is exactly what you want as a requirement.

Change the code to make the requirement passed once the object leaves the screen. Do not be confused by the word pass that is already here. That has nothing to do with The final code should look like this:

extends "res://requirements/base.gd"

func _on_VisibilityNotifier2D_screen_exited():
    passed = true

This way you've made a real requirement that should be moved off-screen before it passes. Before we can do that though, we need one more thing. That is a second level to go to.

Create a New Scene, choose Node2D as root node, and save it in levels as 002.tscn. Leave it empty for now.

Now go back to level 001. Choose a block in your building and click it. You should see it selected in the Scene tab. Now from the FileSystem tab drag the off-screen.tscn and drop it on the selected block.

Click the added OffScreen, then click the Inspector tab. At the top you should see: Next Level. Click the field and enter 001. That is the filename of the level without .tscn.

Now run the game and see what happens when you knock this chosen block off-screen. As soon as it flies off screen, you'll see the empty screen of level 2. Now you can build level 2, and add another block there that must be knocked off screen.

There are many possibilities now:

  • You are not limited to one requirement.
  • Not every requirement has to go to the same level.
  • You could add walls to level 2, so it is harder to knock the target block off screen.
  • You could create an object that has the level itself as Next Level value. If that block leaves the screen, you've failed and the level resets.
  • You could set the _Elastic Strength_value of a ball to a negative value, so you push it instead of pulling it.
  • You can even use this to create a sort of main menu for the game! Which block you knock away determines to which level you go.
  • You can create new requirements scenes with different logic to set the passed value.

Have fun!