📜 ⬆️ ⬇️

Urho3D Editor (Part 2)

We continue to comprehend the editor Urho3D. In this lesson we will learn how to work with physics, get to know the prefabs, master the particle editor and make our gun shoot. And also, as a bonus, learn how to pack game resources.

Physics


Urho3D supports two physical libraries: Box2D and Bullet. The principles of working with them are very similar, however, the first implements the movement of nodes only in the XY plane, and the second in three-dimensional space. The Box2D components are in the Create-> Component-> Urho2D menu, and the Bullet in the Create-> Component-> Physics menu.

So, load the GameData \ Scenes \ Level01.xml scene from the last lesson (File-> Open recent scene or File-> Open scene ...). We have a floor and a gun. Let's add a cannonball to the scene. In the Resource Browser, open the Models folder and drag Cannonball.mdl into the Hierarchy window on the root Scene. To prevent the gun and the floor from interfering with the work, in the Hierarchy window, right-click on their nodes and select Enable / disable. In this case, they will disappear from the scene, and the nodes will be painted red. Now double-click on the node with the kernel and it (the kernel) will be in the center of the screen.


')
Now in the resource browser, open the Materials folder and drag the material onto the StaticModel component in the Hierarchy window or in the Material column of the Attribute inspector window. Give the node a name and turn on the Cast Shadows option.



Add the RigidBody and CollisionShape components (Create-> Component-> Physics) to the cannonball. At the same time, the PhysicsWorld component will be automatically added to the scene, which is necessary for the work of physics.

RigidBody defines the physical properties of an object. Bodies are static and dynamic. Static bodies are fixed and are only obstacles, and dynamic are subject to external forces (including gravity). If the body has a mass - it is dynamic, if the mass is zero, then the body is static.

Give RigidBody weight, sliding friction and rolling friction as in the screenshot below. I want to draw your attention to the parameters of the CCD Radius and CCD Motion Threshold. If small objects at high speeds slip through obstacles, then setting these parameters will help you.



CollisionShape determines the shape of the object that is used when calculating collisions. Why not use the 3D model itself? In order to optimize. For example, to determine the intersection with a sphere, it is sufficient to compare the distance to the center of the sphere and the radius of this sphere. It is much faster than calculating the intersections of a set of triangles. An object can contain several shapes for a more accurate description of the form.

Select the Sphere type for the CollisionShape component and set the radius close to the radius of the cannonball, as in the screenshot above.

Make sure the RevertOnPause switch is activated and click the RunUpdatePlay button. The cannonball under the action of gravity will begin to fall down. Click pause and the kernel will return to its place.

Prefabs


Those who worked with Unity will be familiar with this concept. A prefab is an object template that can be repeatedly inserted into the scene. Create an Objects folder in the GameData directory. Select the Cannonball node, select the menu item File-> Save node as ... and save to the GameData / Objects / Cannonball.xml file. Now the cannonball can be removed from the scene. To add prefabs to the scene, use the menu item File-> Load node.

Gun, shoot!


Turn on the gun node and the floor so that they can be seen. Create RigidBody and CollisionShape components for them. For the floor, select the type of StaticPlane shape (infinite plane) and set (semi) sliding friction and rolling friction equal to one (otherwise the bodies will move along it endlessly, since the contact factors multiply their friction coefficients). For the gun, select the shape type of Capsule and set the shape (not node) Size = (2, 4.3, 1) and Offset Position = (0, 1.12, 0). For the gun, also add an AnimationController component (Create-> Component-> Logic), which will allow us to play the animation of the shot created in the 3D editor.

Now modify the GameData \ Scripts \ Cannon.as gun script (click to expand).
class Cannon : ScriptObject { //      . int direction = 1; //    . float shootDelay = 0.0f; //    . void Update(float timeStep) { //     x (node   ,    ). float pitch = node.rotation.pitch; //   ,       . if (pitch >= 70.0f) direction = -1; else if (pitch <= -10.0f) direction = 1; pitch += 30.0f * direction * timeStep; node.rotation = Quaternion(pitch, 0.0f, 0.0f); if (shootDelay > 0.0f) shootDelay -= timeStep; //          , if (input.keyDown[KEY_SPACE] && shootDelay <= 0.0f) { Shoot(); //   shootDelay = 1.0f; //       . AnimationController@ animCtrl = node.GetComponent("AnimationController"); animCtrl.SetTime("Models/Shoot.ani", 0.0f); //    . animCtrl.PlayExclusive("Models/Shoot.ani", 0, false, 0.0f); //   . SoundSource3D@ source = node.CreateComponent("SoundSource3D"); //   . Sound@ sound = cache.GetResource("Sound", "Sounds/Shoot.wav"); source.autoRemove = true; //       . source.Play(sound); } } void Shoot() { //    CannonballPlace  . Vector3 position = node.GetChild("CannonballPlace", true).worldPosition; //    . XMLFile@ xml = cache.GetResource("XMLFile", "Objects/Cannonball.xml"); Node@ newNode = scene.InstantiateXML(xml, position, Quaternion()); //   RigidBody. RigidBody@ body = newNode.GetComponent("RigidBody"); //       ,        //     .     . body.ApplyImpulse(node.rotation * Vector3(0.0f, 1.0f, 0.0f) * 15.0f); } } 

Launch and enjoy how when you press the space gun inflates and spews the nucleus.

Let's make sure that the kernels after ten seconds of their existence self-destruct. Create a CannonBall.as file in the GameData \ Scripts folder with the text:

 class Dying : ScriptObject { float time = 0.0f; void Update(float timeStep) { time += timeStep; if (time > 10.0f) node.Remove(); } } 

Then load the GameData / Objects / Cannonball.xml prefab into the scene (File-> Load node-> As replicated / local ...), add the ScriptInstance component to it, specify the newly created file and enter the name of the Dying class (remember to press Enter). Now the prefab can be saved and removed from the scene. Run and see how the kernels disappear.

Rabbit town


Add to the scene of the construction of the cubes, which we will fire from a cannon. As usual, drag the GameData / Models / Cube.mdl model onto the root of the Scene node and set it the GameData / Materials / Cube.xml material. Also enable the Cast Shadows option. Add the RigidBody component (Mass = 1, Friction = 1, Rolling Friction = 0.2) and the CollisionShape component (Shape Type = Box, Size = (2, 2, 2)). Place the cube slightly above the ground (if you submerge it in the ground, it will jump out at launch). Press Ctrl + D to duplicate the cube and slide the copy sideways. Create another copy.



By the way, did you notice that in the Attribute inspector window all values ​​that differ from the default ones are marked in golden color?

Now select the entire row of cubes with the Ctrl button pressed and duplicate it entirely. Lift a copy above the first row (do not forget about the gaps). Then create another row.



Run it. We had such a problem that after launching the cubes are slightly lowering down, but manually placing them on each other with great accuracy is difficult. And here the RevertOnPause switch will come to our aid. Turn it off and turn off the gun's ScriptInstance component (just as we previously turned off the entire node, just right-click on the component instead of the node; another way is to click the cross in the Attribute inspector window).



Now start the playback, and when the cubes fall, stop. The scene remained in the new state. Remember to turn on RevertOnPause and ScriptInstance again.

Particles


Let's create a train of particles for cannonballs. Open the particle editor through the menu item View-> Particle editor. Set the following parameters:


Now let's add a color change over time for the particles. Double-click the New button under the Color Frames block to create two new lines and fill in the fields as in the screenshot below. The first value is time, and then the color is in RGBA format.



Click the Save As button, save the effect to the GameData \ Particle \ Sparks.xml file and close the particle editor window. Load a prefab with a cannonball into the scene, add the ParticleEmitter component (Create-> Component-> Geometry) to it, specify the newly created effect, save the prefab to a file and delete the cannon-ball from the scene. The game is ready.

What's next?


We did not consider all the features of the editor. For example, not a word was said about the creation of the interface or about the editor of materials. However, understanding the general principles, it is easy to deal with them.

Now you need to arrange the game as a separate program. The plan is very simple: create a minimal script that loads and runs the scene. But in the scene there is not enough camera, but the internal camera of the editor is used, which will not be available outside of it. As usual, create a new node and add a Camera component to it (Create-> Component-> Scene). Be sure to set the node name Camera so that we can refer to it in our script. Position and rotate the camera as you like (this will help you view from the camera, which appears in the lower right corner). Also attach a SoundListener component (Create-> Component-> Audio) to the camera node, without which you will not hear sounds positioned in space. Save the scene and create a GameData \ Scripts \ Main.as file with the following contents:

 Scene@ scene_; void Start() { scene_ = Scene(); //    . scene_.LoadXML(cache.GetFile("Scenes/Level01.xml")); //      . Node@ cameraNode = scene_.GetChild("Camera"); //  ,       . Viewport@ viewport = Viewport(scene_, cameraNode.GetComponent("Camera")); renderer.viewports[0] = viewport; //     ,     . renderer.shadowMapSize = 2048; //    ,     . audio.listener = cameraNode.GetComponent("SoundListener"); } 

Copy the folder CoreData and launcher Urho3DPlayer.exe in the folder with the game. And we already have a batch file for launching Start.bat (from the archive Urho3DHabrahabr02Start.zip). He points the folder to the launcher, which contain game resources, window sizes and a startup script.

 start "" Urho3DPlayer.exe Scripts/Main.as -p "GameData;CoreData" -w -x 800 -y 600 

The final result can be downloaded here .

Promised Bonus


First, let's compile all the scripts with the “ScriptCompiler.exe GameData / Scripts / *. As” command. As a result, we obtain files with .asc extensions. Recently, a patch has been added, due to which, in the absence of the requested .as file, an .asc file is loaded, which means that now there is no need to rename. Just move the original .as files from the GameData \ Scripts folder to another location, leaving only the .asc files.

For the package we need the utility Build \ bin \ tool \ PackageTool.exe. Run the commands:

 PackageTool.exe CoreData CoreData.pak -c PackageTool.exe GameData GameData.pak -c 

The "-c" option activates file compression (using the LZ4 speed algorithm).

Now folders CoreData and GameData can be removed. As a result, we have:



Well, to be completely beautiful, you can get rid of the batch file Start.bat. But for this you need to modify the source code of the launcher (it is in the folder Urho3D \ Source \ Tools \ Urho3DPlayer). Do not be frightened in advance - the source launcher is very small, because it deals only with the fact that it passes the launch parameters to the engine. These are the parameters you need to specify. At the same time, you can make your own icon for the application.

Instead of conclusion


I take this opportunity to invite those who wish to join the filling of the Russian-language Wiki . Thanks for attention!

Source: https://habr.com/ru/post/265837/


All Articles