Oct 23, 2021Kuina-chan
This is the tutorial 7 to learn the basic features of Kuin Programming Language for exe execution environment. This time, let's make a 3D racing game.
This time I will make a 3D racing game. The completed screen is shown in Figure 1-1.
First, create a 3D model of the car to be used in the game with your favorite tool and output it in .fbx format. In this tutorial, you can use samples/free_resources/obj_car.fbx as a sample.
The .fbx format is a common format for 3D models, but it is not efficient for loading into programs, so convert it to the more efficient Kuin binary format .knobj.
Start the Kuin editor, select "Tools > 3D Model Converter..." from the menu, select the fbx file from "..." and press the "Convert" button, and the knobj file will be output in the same folder as the fbx file after a while (Figure 1-2).
Note that fbx files must have all polygons triangulated. Make sure to triangulate fbx files before saving them.
The 3D Model Converter checkboxes are shown in Table 1-1, although we will not use them in this tutorial.
|Write Tangents And Binormals||Calculates tangent and bynormal from UV and writes them to knobj. Normal maps will be available, but the data will be large and the rendering may be corrupted if the UVs are degenerate. If you do not want to use the normal map, turn this off.|
|Write Joints||Writes the bone and bone animation to knobj. The maximum number of bones that can affect a single vertex is two. The maximum total number of bones is 256. If you do not want to move the bones, turn this off.|
When the knobj file is output, close the 3D Model Converter dialog, press Ctrl+S to save the main kn file, and then press Ctrl+Shift+R to move the knobj file under the res folder that appears, renaming it obj_car.knobj.
Also, prepare a texture to put on the 3D model under the res folder with the name tex_car_albedo.png. This time, copy and place samples/free_resources/tex_car_albedo.png as a sample.
In addition, let's copy the files we will use from the samples/free_resources folder. Copy and place tex_field_albedo.jpg, tex_sky_albedo.png, tex_wall_albedo.jpg, and map_sample_racing.txt (Figure 1-3).
Now let's start drawing the 3D model. Insert the code for "main And A draw Control" from the snippet as shown in the 2nd tutorial, and add the code shown in Figure 2-1.
Lines 3 and 4 declare the variables for the 3D model and texture image, and lines 10 and 11 load them from a file.
Line 12 is the Z-buffer setting for resolving the back and forth relationship of depth. The arguments in parentheses in the draw@depth function are, in order, whether the Z test is enabled and whether Z writing is enabled. Normally, when drawing 3D, enable it and set it to "draw@depth(true,true)", and when drawing 2D at the forefront, set it to "draw@depth(false,false)".
In line 15, a 3D model with a texture on its surface is drawn on the screen. The arguments in parentheses in the draw method are, in order, mesh index, animation frame, diffuse map texture (color reflection), specular map texture (gloss), and normal map texture (unevenness).
The camera and lights are set to be somewhat easy to use without any settings. When you run it, the car will be displayed (Figure 2-2).
Next, let's draw the ground and shadows.
The ground is created by applying a texture to a mere flat surface. If you just want to create a simple 3D model like a plane, you don't need to prepare a .knobj file, you can create it from a function.
To draw a shadow, first create an instance of the draw@Shadow class, register the 3D model that will cast the shadow, and then use the drawWithShadow method instead of the draw method (Figure 3-1).
Don't forget to change line 27 as well.
A planar model representing the ground is created in line 16, and its position and size are adjusted in line 17. The arguments in parentheses in the pos method are, in order, expansion X, expansion Y, expansion Z, rotation X, rotation Y, rotation Z, position X, position Y, position Z.
In line 19, a shadow buffer is created, and in lines 22 to 24, the model that will cast the shadow is registered. To register a shadow, add models with the add method in the beginRecord and endRecord enclosures as shown here.
In the parentheses of beginRecord in line 22, the range for calculating the shadow is specified as a sphere. The arguments are, in order, sphere position X, position Y, position Z, and sphere radius. If you make the sphere too large, the shadows will be coarse, and if you make it too small, the shadows outside the sphere will not be drawn.
When you run it, it will look like Figure 3-2.
Finally, it's time to move the car.
As in Side View Action Game, the position of the car is managed by a class that inherits from game@Rect (Figure 4-1).
Don't forget to change line 54 as well.
The angle in the 2nd line represents the angle that the car is facing. Lines 26 to 31 create an instance of the Car class, and lines 34 to 50 process the movement of the car. This is the same as for the Side View Action Game.
The camera is set up in line 51. The arguments in parentheses for draw@camera are, in order, camera position X, position Y, position Z, camera gazing point X, gazing point Y, gazing point Z, and direction X that the top of the camera will face, direction Y, and direction Z. Here I have set up the camera so that it always shows the car from diagonally behind it.
The position of the car is set in line 52. In line 54, I limit the creation of shadows to the area around the car, which is the area often seen by the camera.
When you run it, it will look like Figure 4-2.
Press the A button on the gamepad or the Z key on the keyboard to start the car. Press B or X key to move backward. Press the Left/Right button or the Left/Right key while the car is running to turn the car around.
Finally, let's draw the sky and walls. Both the sky and the walls will be drawn as cubes.
As in the Side View Action Game, the walls are mapped in a text file and handled by the game@Map class. The collision detection is the same as in the Side View Action Game (Figure 5-1).
In lines 30 and 33, cube models is created using the draw@makeBox function.
The sky is represented by a giant cube that wraps around the world. For this reason, the surface of the cube polygon needs to face inward, and I have flipped it over in line 31 by setting the Z axis scaling to negative.
When you run it, it will look like Figure 5-2.
The car will hit the wall properly. You can play with the car to make it run a lap faster, or modify the stages and programs.
That's it, the 3D racing game is complete. Next time, let's try competitive programming.