Tutorial (Godot Engine v3 - GDScript) - Physics (Verlet vs RigidBody)!

in #utopian-io7 years ago (edited)

Godot Engine Logo v3 (Beginner).png Tutorial

<p dir="auto"><img src="https://images.hive.blog/768x0/https://steemit-production-imageproxy-thumbnail.s3.amazonaws.com/DQmeRXYK5hTURHD9TqUuGi4vPsockATFzcKFZdawUYpq24B_1680x8400" srcset="https://images.hive.blog/768x0/https://steemit-production-imageproxy-thumbnail.s3.amazonaws.com/DQmeRXYK5hTURHD9TqUuGi4vPsockATFzcKFZdawUYpq24B_1680x8400 1x, https://images.hive.blog/1536x0/https://steemit-production-imageproxy-thumbnail.s3.amazonaws.com/DQmeRXYK5hTURHD9TqUuGi4vPsockATFzcKFZdawUYpq24B_1680x8400 2x" /> ...learn about Verlet Integration! <h1>What Will I Learn? <p dir="auto">Hi, welcome back! <p dir="auto">I posted an <a href="https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-i-m-prototyping" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">update last week to state why I'd not continued recently with any of my tutorials. This was due to a combination of real-life work and prototyping the Invader movement for the 'Space Invaders' clone (as being built in the Beginner's Tutorial set). <p dir="auto">As part of the prototyping, I stumbled across several different types of Physics implementation; I'd assumed there was only one way to do 'gravity' physics, how wrong could I be? <blockquote> <p dir="auto">Why did I even bother looking at physics engine? After all, Godot Engine has its own! <p dir="auto">This statement is true, but for me, to accept and partially to understand how the engine works, I wanted to refresh my Physics understanding. <p dir="auto">Further to this, I have a need to develop a few effects that won't rely on the inbuilt physics engine but rather, require a physics "feel". <blockquote> <p dir="auto">Yes, the inbuilt physics engine provides an amazing capability, especially given it utilises hardware acceleration! I.E. If you export to the PC and you have a modern GFX card, it is going to calculate the physics way faster than any CPU code can! <p dir="auto">IF however, you are building a game that is more 'Sprite' based; i.e. it does not rely on physics, creating a hybrid is hard! I.E. the "Space Invaders" clone would work as utilising the physics engine, but actually, it'd be overkill! <em>(my opinion) <p dir="auto">The game doesn't need all the collision detection and spatial awareness it contains. It is possible to hook custom code to it but there is a need to tread carefully. It is important to protect timings and avoid delays. <blockquote> <p dir="auto">In a nutshell, the Physics engine is too heavyweight for the needs for this game; but is most likely appropriate for others! <p dir="auto">In my search for Physics information, I stumbled on this brilliant <a href="https://www.youtube.com/watch?v=3HjO_RGIjCU" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">youtube video - Coding for Maths tutorial! There are 3 parts, watch them all! The speakers' tone, speed and the quality of education are second to none! What are you waiting for? <p dir="auto">Everything in that tutorial is reflected in the Verlet code below, that I've re-engineered into a Godot Engine usable form; I believe he is using Javascript in the video. <p dir="auto">I don't wish to be called out for plagiarism, that is NOT my goal. Therefore, this material is attributed to the 'Coding for Maths' set. <p dir="auto">However, I felt a need to provide this code in Godot Script form, because it will be used as the basis for several other tutorials, i.e. I have a swing/chain bridge type effect and a swinging rope! These could easily be adopted into a non-physics game (I have ideas for them! I.E. in the cut-the-rope form and a few platform type ideas) <p dir="auto">By laying the foundations here, with the Box example that is in the video, I'm going to set out the principles for your use; if you do not have a need to use the out-of-the-box features! <p dir="auto">I will also provide a detailed explanation of how to use the in-built Physics too! So you can see them and compare the difference. In that way, you can decide on whether the out-of-the-box capability is the right option! If you don't believe it is, you have other choices, please remember that.<br /> <center><br /> <img src="https://images.hive.blog/0x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521398187/ejeyyqhh986j3xspeuz1.gif" alt="Both Physics.gif" /><br /> <br /> <center>Note: the recording method does so at 30fps<br /> <center>, therefore, it ruins the quality throughout this article! <hr /> <h3>Assumptions <blockquote> <ul> <li>You have installed <a href="https://steemit.com/gamedev/@sp33dy/installing-godot-engine-v3-0-windows" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Godot Engine v3.0 <li>You are familiar with GDScipt <h3>You will <ul> <li>Add a Verlet Box <li>Add an out-of-the-box physics box <li>Add a GUI <h1>Requirements <p dir="auto">You must have installed <a href="https://steemit.com/gamedev/@sp33dy/installing-godot-engine-v3-0-windows" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Godot Engine v3.0. <p dir="auto">All the code from this tutorial is provided in a <a href="https://github.com/sp33dy/Godot-v3-Tutorials-Competent" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">GitHub repository. I'll explain more about this, towards the end of the tutorial. You may want to download this <hr /> <h1>Add a Verlet Box <p dir="auto">Please watch the <a href="https://www.youtube.com/watch?v=3HjO_RGIjCU" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">first and second video. I have re-engineered the code into Godot Script. You may download this from the GitHub repository (see below) or you will need to piece the following script together: <pre><code>extends Node2D onready var SCREEN_SIZE = get_viewport().size <blockquote> <p dir="auto">A new <em>VertletBox was created as a Node2D and a script added, hence the extends<br /> The screen size is obtained when the Node is <em>ready <pre><code>var points = [ { pos = Vector2(0,0), oldPos = Vector2(0,0)}, { pos = Vector2(100,0), oldPos = Vector2(100,0) }, { pos = Vector2(100,100), oldPos = Vector2(100,100)}, { pos = Vector2(0,100), oldPos = Vector2(0,100)} ] <blockquote> <p dir="auto">A dictionary, like the Javascript version in the tutorial is used to store the point positions; both current and old <pre><code>var sticks = [ { p0 = 0, p1 = 1 }, { p0 = 1, p1 = 2 }, { p0 = 2, p1 = 3 }, { p0 = 3, p1 = 0 }, { p0 = 0, p1 = 2, hide = true } ] <blockquote> <p dir="auto">A second dictionary, to store the sticks (links between points) is used. <pre><code>var smoothing = 5 var bounce = 0.9 var gravity = 0.2 var resistance = 0.98 var friction = 0.90 <blockquote> <p dir="auto">The environment variables are set: <blockquote> <ul> <li>Smoothing being the number of iterations to allow the sticks and points to settle <li>Bounce being the adjustment after a collision with a wall or floor <li>Gravity being the velocity adjustment of a box down <li>Resistance being the 'air resistance' as the box travels in the air <li>Friction being the adjustment as the box travels over the floor <pre><code>func _ready(): pickThrow() calcSticks() <blockquote> <p dir="auto">The <em>ready function picks a velocity to move the box initially (i.e. throw it) <blockquote> <p dir="auto">It then calculates the position of the sticks, placing additional entries into the dictionary, such as calculating the length between them <pre><code>func pickThrow(): randomize() points[0].oldPos.x = randf() * 250.0 <blockquote> <p dir="auto">The <em>pickThrow function sets the x-axis of the old position of the first point to some random value; this forces the 'sticks' to shuffle themselves and causes an initial momentum <pre><code>func calcSticks(): for stick in sticks: stick.p0 = points[stick.p0] stick.p1 = points[stick.p1] stick.length = stick.p0.pos.distance_to(stick.p1.pos) $Frame.add_point(stick.p0.pos) <blockquote> <p dir="auto">For each tick, get the distance from the first point to the second and store it back in the dictionary as well as adding the point to the child <em>node named "Frame" (which is a Line2D Node). The Line2D does exactly what is in its name, by constructing a line or set of lines based on configured points; therefore each required point is added to it (5 of them) resulting in a box to be formed <pre><code> func _process(delta): updatePoints() for i in range (smoothing): updateSticks() constrainPoints() renderFrame() <blockquote> <p dir="auto">The frame <em>process function is identical to that in the video tutorial. The points are updated, the sticks and points are allowed to sort themselves out over a number of smoothing iterations. Finally, the frame is rendered <pre><code>func updatePoints(): for point in points: applyMovement(point) func applyMovement(point): var velocity = calcVelocity(point) point.oldPos = point.pos point.pos += velocity point.pos.y += gravity func calcVelocity(point): var velocity = (point.pos - point.oldPos) * resistance if int(point.pos.y) == SCREEN_SIZE.y: if int(point.oldPos.y) == SCREEN_SIZE.y: velocity *= friction return velocity <blockquote> <p dir="auto">The <em>updatePoints function is spread across three. The first loops through each point and calls the <em>applyMovement (easily deduced) <blockquote> <p dir="auto">The <em>applyMovement then calls the <em>calcVelocity function, to do exactly that! The current position is stored in the old. The velocity is then added to the pos and Gravity is added on top (as per the video explanation) <blockquote> <p dir="auto">The <em>calcVelocity function uses the Verlet way to calculate the velocity by subtracting the old position from the current position and multiplying it by any air resistance. A check is made to determine if the point before and now, where touching the floor, if so, apply the friction! I.E. if the two are the same as the screen height, it must have travelled along the floor and no vertical movement was had. <pre><code>func updateSticks(): for stick in sticks: var d = stick.p1.pos - stick.p0.pos var distance = stick.p1.pos.distance_to(stick.p0.pos) var difference = stick.length - distance var percentage = difference / distance / 2 d *= percentage stick.p0.pos -= d stick.p1.pos += d <blockquote> <p dir="auto">The first function in the smooth iteration readjusts the sticks to ensure their lengths comply; as per the video <pre><code>func constrainPoints(): for point in points: screenBounce(point) func screenBounce(point): var velocity = calcVelocity(point) bounce(point, "x", SCREEN_SIZE.x, velocity) bounce(point, "y", SCREEN_SIZE.y, velocity) func bounce(point, axis, size, velocity): if point.pos[axis] >=0 and point.pos[axis] <= size: return rebound(point, axis, size, velocity) func rebound(point, axis, size, velocity): point.pos[axis] = (size if point.pos[axis] > 0 else 0) point.oldPos[axis] = point.pos[axis] + velocity[axis] * bounce <blockquote> <p dir="auto">The second part of the iteration ensures points remain onscreen; with a bounce, as per the video <pre><code>func renderFrame(): for i in range (sticks.size()): $Frame.set_point_position(i, sticks[i].p0.pos) <blockquote> <p dir="auto">After the smoothing iterations, the final call is to render the points. This is achieved by setting the original positions in the child Line2D Node (<em>Frame) to the newly calculated positions. By doing so, the rectangle moves and is shown onscreen. <p dir="auto">The new Scene <em>VerletBox can be attached to any display scene and it will fall to the ground as expected. <p dir="auto">As stated, the BEST explanation is provided in the video; so please do watch that. <p dir="auto">I've provided this code to demonstrate how it works in Godot Engine. I'm going to return to this over the next few tutorials but felt readers should become familiar with this technique. There are others, but I like how it is explained. Taking its concepts, transferring them into Godot's becomes easier. <h1>Add an out-of-the-box physics box <p dir="auto">To implement a box in the physics engine, a few new <em>Node types have to be used and learnt. Let's start from the beginning! <p dir="auto">The <a href="http://docs.godotengine.org/en/3.0/tutorials/physics/physics_introduction.html" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">documentation is a good place to look. <blockquote> <p dir="auto">We will create a RigidBody Node, that will fall to the floor with physics, i.e. as did the Verlet Box. <p dir="auto">Create a new Scene and add a RigidBody as the root Node and name it what you like (I called mine PhysicsBox): <p dir="auto"><img src="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521406463/c0cityyf3xca5gr6abo7.png" alt="image.png" srcset="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521406463/c0cityyf3xca5gr6abo7.png 1x, https://images.hive.blog/1536x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521406463/c0cityyf3xca5gr6abo7.png 2x" /> <p dir="auto">As you can see, we also need to add a CollisionShape2D next. This is mandatory because a little yellow triangle is shown in the RigidBody until one is. The collision shape defines an area that is used to determine a collision; without it, physics doesn't work in the engine! This is the distinguishing point I'm making between Godot's out-of-the-box engine and the Verlet implementation. Godot requires specific <em>Nodes to work. <p dir="auto">Add the CollisionShape2D and then look at the Inspector: <p dir="auto"><img src="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521406680/oqykwxgnkwbnhqkhyon6.png" alt="image.png" srcset="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521406680/oqykwxgnkwbnhqkhyon6.png 1x, https://images.hive.blog/1536x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521406680/oqykwxgnkwbnhqkhyon6.png 2x" /> <p dir="auto">Click the Shape property and select RectangleShape2D: <p dir="auto"><img src="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521406718/iotnpp2hw3davgmgw451.png" alt="image.png" srcset="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521406718/iotnpp2hw3davgmgw451.png 1x, https://images.hive.blog/1536x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521406718/iotnpp2hw3davgmgw451.png 2x" /> <p dir="auto">As you can see in the options, you can define the shape as a Rectangle, Circle, Capsule or even define a convex or concave shape. Your choice should always reflect the shape you are adding to the real world. When their shape areas overlap, collisions occur, hence they should encapsulate the image perfectly! <p dir="auto">Now the RectangleShape2D is added, we need to define the size of the shape, thus click the pull-down option on the right: <p dir="auto"><img src="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521406845/eosfbrsaxkfapkruchlq.png" alt="image.png" srcset="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521406845/eosfbrsaxkfapkruchlq.png 1x, https://images.hive.blog/1536x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521406845/eosfbrsaxkfapkruchlq.png 2x" /> <p dir="auto">..and select Edit: <p dir="auto"><img src="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521406867/okvlgfiol5bl6btb2coc.png" alt="image.png" srcset="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521406867/okvlgfiol5bl6btb2coc.png 1x, https://images.hive.blog/1536x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521406867/okvlgfiol5bl6btb2coc.png 2x" /> <p dir="auto">Please edit the extent and set it to 50 x 50 (the size is half the final size): <p dir="auto"><img src="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521406926/oxg6pseca3s6sqhbtqv8.png" alt="image.png" srcset="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521406926/oxg6pseca3s6sqhbtqv8.png 1x, https://images.hive.blog/1536x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521406926/oxg6pseca3s6sqhbtqv8.png 2x" /> <p dir="auto">We will define a 100 x 100 pixel Box, thus 50 x 50 is the correct extent. <p dir="auto">Finally, we need to add the Line2D shape. This could be a Sprite or another Node2D, but this matches the <em>Frame Line2D shape in the Verlet Box Node. <p dir="auto">When added, go to the Inspector and click on Points property that shows Vector2: <p dir="auto"><img src="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521407089/us2glkbuxsrqnav2eidp.png" alt="image.png" srcset="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521407089/us2glkbuxsrqnav2eidp.png 1x, https://images.hive.blog/1536x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521407089/us2glkbuxsrqnav2eidp.png 2x" /> <p dir="auto">This will open a second panel that allows us to define 5 points. Set the size to 5 and provide the following configuration into the array: <p dir="auto"><img src="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521407151/prnkn3yhdyky9erfe8kj.png" alt="image.png" srcset="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521407151/prnkn3yhdyky9erfe8kj.png 1x, https://images.hive.blog/1536x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521407151/prnkn3yhdyky9erfe8kj.png 2x" /> <p dir="auto">If you click the RigidBody node and look at the 2D View: <p dir="auto"><img src="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521407189/b0qjv7uf0xysnyy5hkea.png" alt="image.png" srcset="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521407189/b0qjv7uf0xysnyy5hkea.png 1x, https://images.hive.blog/1536x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521407189/b0qjv7uf0xysnyy5hkea.png 2x" /> <p dir="auto">You should have a box outline with a shaded centre (the collision area). Mine is red and has a thin border, as I set these in the Line2D Inspector window. <p dir="auto"><img src="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521407353/ayrtfjsbwbchynt1hedf.png" alt="image.png" srcset="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521407353/ayrtfjsbwbchynt1hedf.png 1x, https://images.hive.blog/1536x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521407353/ayrtfjsbwbchynt1hedf.png 2x" /> <p dir="auto">Congratulations, you now have a Godot Engine Physics node! If you drop it into a Game Scene, watch what it does: <p dir="auto"><center><br /> <img src="https://images.hive.blog/0x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521407456/auuykjskftg1jzhwygrk.gif" alt="Now you see it, now you dont.gif" /><br /> <p dir="auto">..oh! It drops from the sky and disappears off the bottom of the screen! <p dir="auto">The Godot Engine does not have a 'Floor' per say. It is open-ended for developers to use as they see fit. <h4>Walls and Floors <p dir="auto">If you need a floor or walls; or both, you will need to build them with other physic Nodes!!! Hence why there is one readily available, known as StaticBody2D! <p dir="auto">We're going to create a floor and the left/right borders. Open a new scene and add a Node2D as the root Node (I named mine Borders). This is what we want to form: <p dir="auto"><img src="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521408272/chlndqqi3fxnrpciwig0.png" alt="image.png" srcset="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521408272/chlndqqi3fxnrpciwig0.png 1x, https://images.hive.blog/1536x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521408272/chlndqqi3fxnrpciwig0.png 2x" /> <p dir="auto">What you are looking at, are three strips of Static Bodies, which ensure no moving Physic's bodies shall pass by them; i.e. they act like lines of bricks! <p dir="auto">Add a StaticBody2D and name it 'Floor'. You'll note a yellow triangle appears (again), to let you know you need a Collision Shape: <p dir="auto"><img src="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521409185/jwcd8vxvn8lxy9hubkwu.png" alt="image.png" srcset="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521409185/jwcd8vxvn8lxy9hubkwu.png 1x, https://images.hive.blog/1536x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521409185/jwcd8vxvn8lxy9hubkwu.png 2x" /> <p dir="auto">So, let's add one: <p dir="auto"><img src="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521409229/notjael6weuv7zd58hmk.png" alt="image.png" srcset="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521409229/notjael6weuv7zd58hmk.png 1x, https://images.hive.blog/1536x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521409229/notjael6weuv7zd58hmk.png 2x" /> <p dir="auto">As with the Collision Shape for the Box, set it to Rectangle and set its extent to 512 x 10 (half of screen width and we'll have a wall of 20 pixels in height) <p dir="auto">Finally, set the Position property of the Floor StaticBody2D to 512 x 610: <p dir="auto"><img src="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521409335/ic0kgc2yhyx1j428acjp.png" alt="image.png" srcset="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521409335/ic0kgc2yhyx1j428acjp.png 1x, https://images.hive.blog/1536x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521409335/ic0kgc2yhyx1j428acjp.png 2x" /> <p dir="auto">The Body will then appear below the bottom of the screen, but perfectly in parallel to it. <p dir="auto">Try adding the Borders Scene to the Game Scene, like so: <p dir="auto"><img src="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521409683/serphvfw9vhzyujbwr3k.png" alt="image.png" srcset="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521409683/serphvfw9vhzyujbwr3k.png 1x, https://images.hive.blog/1536x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521409683/serphvfw9vhzyujbwr3k.png 2x" /> <p dir="auto">Try rerunning the Game: <p dir="auto"><center><br /> <img src="https://images.hive.blog/0x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521409802/asb68vmycr4gotmcduib.gif" alt="bouncing box.gif" /><br /> <p dir="auto">The box now bounces nicely!!! The Floor is doing its job. <h4>Throwing the box <p dir="auto">In the Verlet box code, a <em>throw function ensures that each new box receives a slightly different speed and direction, each time. Let's implement this in the RigidBody2D Box. Please attach a Script and add the following code: <pre><code>extends RigidBody2D func _init(): angular_velocity = randf() * 5.0 linear_velocity = Vector2(randf() * 700.0, 0.0) <blockquote> <p dir="auto">Extend the RigidBody2D class <blockquote> <p dir="auto">Set the angular velocity (spin) to something between 0.0 and 5.0 <blockquote> <p dir="auto">Set the linear velocity (direction) to something between 0.0 and 700.0 pixels per second in the horizontal axis and default vertical to zero. <p dir="auto">Rerun the game: <p dir="auto"><center><br /> <img src="https://images.hive.blog/0x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521410259/isoenwipdbnonth2dbm8.gif" alt="box over the edge.gif" /><br /> <p dir="auto">...ah! We need borders on the Left and Right, or the box drops off! <h3>Add Left/Right Borders <p dir="auto">Two more Static Bodies should be added to the Borders Scene, much like that for the Floor. I'll let you figure this out, but here are the details: <blockquote> <ul> <li>Left : Extents (10, 300) and Position of (-10, 300) <li>Right : Extents (10, 300) and Position of (1034, 300) <p dir="auto"><em>NOTE: DO NOT BE TEMPTED to duplicate the floor Node to make the other two. If you do, they all inherit the same CollisionShape2D, which is elongated for the floor width; therefore they will not work in the borders. You need to add each of these individually (or you can duplicate the LeftBorder to make the RightBorder if you wish). <p dir="auto">This now works: <p dir="auto"><center><br /> <img src="https://images.hive.blog/0x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521410673/fowlmiohepbuuyefoudg.gif" alt="wall bounce.gif" /><br /> <p dir="auto">... you can just see the box bouncing off the right border! <h1>Add a GUI <p dir="auto">Given we now have two different forms of Physics, we 'could do' with a GUI. I.E. several buttons that can be clicked to produce a random Box and another to clear them! <p dir="auto">Create a new Scene and name it GUI. Add three 'Buttons': <p dir="auto"><img src="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521410990/qgsfsydazhqc1ntyl7i2.png" alt="image.png" srcset="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521410990/qgsfsydazhqc1ntyl7i2.png 1x, https://images.hive.blog/1536x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521410990/qgsfsydazhqc1ntyl7i2.png 2x" /> <p dir="auto">Name them as I: <ol> <li>Clear <li>New Verlet Box <li>New Physics Box <p dir="auto">Set their Rect properties as such: <ol> <li>Clear - (0, 0) <li>New Verlet Box - (100, 0) <li>New Physics Box - (300, 0) <p dir="auto">Click the Clear button and set its text to 'Clear': <p dir="auto"><img src="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521411193/qdv8elwyhfmhe812dkhi.png" alt="image.png" srcset="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521411193/qdv8elwyhfmhe812dkhi.png 1x, https://images.hive.blog/1536x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521411193/qdv8elwyhfmhe812dkhi.png 2x" /> <p dir="auto">This is what is shown in the Game: <p dir="auto"><img src="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521411239/qzxicfn1szi0qlizu19i.png" alt="image.png" srcset="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521411239/qzxicfn1szi0qlizu19i.png 1x, https://images.hive.blog/1536x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521411239/qzxicfn1szi0qlizu19i.png 2x" /> <p dir="auto">Attach an empty Script to the GUI Node and then we will wire the 'clicked' function from each button to the GUI Node script. <p dir="auto">In the Inspector pane, switch to the Node table and double-click the pressed() function: <p dir="auto"><img src="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521411317/wi1e2pfkpzsxhsri1h7i.png" alt="image.png" srcset="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521411317/wi1e2pfkpzsxhsri1h7i.png 1x, https://images.hive.blog/1536x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521411317/wi1e2pfkpzsxhsri1h7i.png 2x" /> <p dir="auto">A new window will pop-up, asking you which Node to connect to, so select the GUI: <p dir="auto"><img src="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521411386/ywdjvuaqd37sizmdxrjt.png" alt="image.png" srcset="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521411386/ywdjvuaqd37sizmdxrjt.png 1x, https://images.hive.blog/1536x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521411386/ywdjvuaqd37sizmdxrjt.png 2x" /> <p dir="auto">...and click the 'Connect' button. <p dir="auto">The script of the GUI Node will open, with a new function _<em>on_Clear_pressed() added. Let's set it to call its parent's <em>clear function. <p dir="auto">In the other two buttons, connect their pressed() functions in the same way. The script should then look like this: <p dir="auto"><img src="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521411766/x0jxkigha5ophy6ixdnr.png" alt="image.png" srcset="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521411766/x0jxkigha5ophy6ixdnr.png 1x, https://images.hive.blog/1536x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521411766/x0jxkigha5ophy6ixdnr.png 2x" /> <p dir="auto">We now need to add the GUI Node as an instance to the Game Node and add these three functions into its own script: <pre><code>extends Node <blockquote> <p dir="auto">Extend a base Node <pre><code>const VERTLET_BOX = preload("res://VerletBox/VerletBox.tscn") const PHYSICS_BOX = preload("res://PhysicsBox/PhysicsBox.tscn") <blockquote> <p dir="auto">Declare constants that have preloaded the two Box Scenes <pre><code>func clear(): for box in $Boxes.get_children(): box.queue_free() <blockquote> <p dir="auto">The <em>clear function looks for all children of the <em>Boxes Node2D Node (you need to add this). By adding this Node, we can ensure all new Boxes are added to it with the safe knowledge that if we remove any child, we clear ALL of them. If you cleared the children of the Game Scene, we'd remove the GUI and Border Nodes! <pre><code>func newVerletBox(): $Boxes.add_child(VERTLET_BOX.instance()) <blockquote> <p dir="auto">The <em>newVerletBox creates a new Verlet Box and adds it to the <em>Box node <pre><code>func newPhysicsBox(): $Boxes.add_child(PHYSICS_BOX.instance()) <blockquote> <p dir="auto">The <em>newPhysicsBox creates a new Physics Box and adds it to the <em>Box node <p dir="auto">Try rerunning the game: <p dir="auto"><center><br /> <img src="https://images.hive.blog/0x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521412402/ee1i68rjhygbmuqzkdty.gif" alt="fully working with gui.gif" /><br /> <p dir="auto">The different types of boxes get created! <p dir="auto">As you should see, the Godot Physics Nodes interact with each other, via collisions! That's the purpose of them. If you want collisions, this implementation is EXACTLY what you need. <p dir="auto">For the 'Space Invaders' clone, we require a simple Sprite based system that is under our complete control; in terms of their position and collision. Using the Physics engine 'could' work, but it would introduce complexity that is not required. We 'could' adopt a hybrid solution, but this too would be more complex than simply designing a Sprites with Area2D's solution; much like the bespoke Verlet physics code. <blockquote> <p dir="auto">Don't be afraid of doing your own thing; but do assess inbuilt features first, before you dismiss them entirely! <h1>Finally <p dir="auto">This tutorial has taken me much longer than I expected! <p dir="auto">I hope it provides you lots of useful information. <p dir="auto">As stated, I intend on expanding this code, deriving a 'chain bridge' and 'swinging rope' example. <p dir="auto">Hopefully, you've watch the principles of the Verlet Integration in the brilliant youtube videos! <p dir="auto">Please do comment and ask questions! I'm more than happy to interact with you. <h1>Sample Project <p dir="auto">I hope you've read through this Tutorial, as it will provide you with the hands-on skills that you simply can not learn from downloading the sample set of code. <p dir="auto">However, for those wanting the code, please download from <a href="https://github.com/sp33dy/Godot-v3-Tutorials-Competent" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">GitHub. <p dir="auto">You should then Import the "Verlet Integration (Boxes)" folder into Godot Engine. <h1>Other Tutorials <h4>Beginners <blockquote> <ul> <li><a href="https://steemit.com/gamedev/@sp33dy/installing-godot-engine-v3-0-windows" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Install Godot Engine 3.0 <li><a href="https://steemit.com/gamedev/@sp33dy/first-demo-godot-engine-v3-0" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Installing your First Demo <li><a href="https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-your-first-moving-sprite" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Your first Sprite! <li><a href="https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-move-your-sprite" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Move your first Sprite! <li><a href="https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-create-lots-of-sprites" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Create lots of Sprites! <li><a href="https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-sprite-formations" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Sprite formations! <li><a href="https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-smooth-movement#comments" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Smooth Movement! <li><a href="https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-invader-graphics" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Invader Graphics! <li><a href="https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-player-ship" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Player Ship! <li><a href="https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-bullets" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Bullets <li><a href="https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-collision-dectection" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Collision Detection! <li><a href="https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-colour-use" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Colour use! <h4>Competent <blockquote> <ul> <li><a href="https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-custom-tilemap" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Custom TileMaps <li><a href="https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-custom-tilemap-scrolling" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Custom TileMap Scrolling <li><a href="https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-generic-screen-wrapping-sprite" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Screen Wrapping Sprite <li><a href="https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-generic-screen-wrapping-node" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Screen Wrap Node
Sort:  

Thank you for the contribution. It has been approved.

You can contact us on Discord.
[utopian-moderator]

Hey @sp33dy I am @utopian-io. I have just upvoted you!

Achievements

  • You have less than 500 followers. Just gave you a gift to help you succeed!
  • Seems like you contribute quite often. AMAZING!

Community-Driven Witness!

I am the first and only Steem Community-Driven Witness. Participate on Discord. Lets GROW TOGETHER!

mooncryption-utopian-witness-gif

Up-vote this comment to grow my power and help Open Source contributions like this one. Want to chat? Join me on Discord https://discord.gg/Pc8HG9x

I just found your Godot tutorials, they are absolutely fantastic! I've been wanting to learn Godot for a while now and these are exactly what I need. You're clearly investing a lot of time on these, Thank you.

Oh, that's fantastic news! I don't get much feedback, other from the Mods. Welcome, and do let me know if you want me to touch on specific topics. I'm new in relative terms (just under a year invested) to Godot, but I'm extremely pleased with it.

I'll let you know if there's any requests that come into mind once I finish going through all of your tutorials. Keep making them please, Godot tutorials are great. Especially now with the release of Godot 3.

Follow, I follow back, let's support each other 😊

I'm surprised by the number of votes on this Post, so thank you! I've tried to fix some of the grammar mistakes, but I'm sure there are plenty more.