Recently, I used ogre + nxogre (a physical engine combining ageia physx and ogre) to create a racing game. I couldn't find any Chinese information on the Internet, so I reprinted this article and hoped to help myself and others.
************ **
From:Http://blog.csdn.net/tonywjd/archive/2006/08/11/1052346.aspx
The game mainly uses several engines, the physical engine (physicsx SDK 2.3.2, the new version of novedex), and the graphic rendering engine (Ogre 1.2.0, including the cegui part of man-machine interfaces ), sound engine (direct sound), network engine (raknet, unfortunately due to time and other reasons, failed to join, greatly reducing game playability), modeling with Maya and 3 DSMAX.
Model Export
Ogre has its own 3D model format (. Mesh format ). You can directly download the export plug-in from the official ogre website. However, there are several bugs in the export plug-in. The export method varies with the modeling method. The export plug-in of Maya cannot export non-closed surfaces, but 3dsmax can, so it can be imported into. mesh.
In addition, to achieve precise collision in the physical engine, it is best to obtain the Grid Structure of the model, that is, the point and Plane Information of the model, rather than being wrapped in a simple rule form. In our game, maps use the former, while vehicle items use the latter.
Physicsx does not support. mesh. Therefore, we use the. mesh. xml file exported by the Export plug-in to read the dot and Plane Information (only this) and then write it to the custom binary file format for the physical engine.
Coupling Between ogre and physicsx
Physicsx and ogre have similar scenario management and corresponding classes. An object that can be moved can be implemented using scenenode in ogre and added to Scenario Management. nxactor can be used in physicsx. Physicsx is a physical unit in nxactor. It can enclose an object with simple geometric shapes. Therefore, gravity, collision, and other physical functions are applied to nxactor, and generate corresponding physical reactions. After obtaining the corresponding physical data, you can set the corresponding scenenode attribute to achieve a realistic physical effect.
In fact, the map scenario is also implemented as a common 3D object.
The ing between ogre and physicsx is not a ing encapsulation for every object. These two parts are encapsulated into two independent modules, but all the objects in these two parts are one-to-one. In the masterProgramAnd transfer the result calculated from physicsx to the ogre part for plotting. This also provides a good embedding point for network addition. As long as the server performs all the physical operations, the calculation result is sent to the ogre client for rendering.
The framestated (const frameevent & EVT) in ogre is called as the main thread of the program.
M_nxscene-> simulate (EVT. timesincelastframe); // m_nxscene, instance of (nxscene *)
M_nxscene-> flushstream ();
M_nxscene-> fetchresults (nx_rigid_body_finished );
Then draw the physical result of the operation to ogre.
In this way, ogre and physicsx are combined, and their internal implementations do not affect each other. They can be programmed independently as long as the one-to-one correspondence between the two objects is handled.
Implementation of map scenarios
Ogre provides dedicated outdoor map Scenario Management. However, it is difficult for a height chart to be imported into physicsx. Unless the vertex and plane information is obtained during modeling, it is difficult for a height chart to be consistent with the grid vertex and plane information in a specific operation. We also tried to get the coordinates of M * n points on the map through the ray of ogre during program initialization, and formed 2 * m * n triangle patches, which were used in the physical engine, similar to physical map. However, the projection of all triangles on the xz Z plane is the same. If there are too few triangles that may be inaccurate, too many triangles will increase unnecessary overhead. In general, this is not ideal.
Physicsx also has an nxactor used to process map scenarios. You can run
Terraindesc. heightfieldverticalaxis = nx_y; // terraindesc is a nxtrianglemeshdes
// Default: nx_not_heightfield
Terraindesc. heightfieldverticalextent =-1000.0f;
. This greatly improves the efficiency. This should have been an ideal practice. However, due to some errors in model export during modeling, some patches may be vertical, and the physical collision effect is too intense in these areas, on the screen, the car will suddenly be hit and fly very high. We haven't found a proper method to export the model for a long time to avoid this phenomenon. Therefore, only the map scenario can be processed as a normal nxactor. Although this problem cannot be overcome during modeling and export, it is difficult for players to detect it.
In this way, the map scenario has the implementation method: In ogre as a normal. mesh treatment, create scenenode and entity. In physicsx, it is treated as a normal nxactor, but it is processed with nxcooking. The specific issue is not detailed, probably to improve performance.
Vehicle implementation
The realization of vehicles is the focus of this game.
Of course, it is also implemented in two parts: ogre and physicsx.
The ogre part also includes the angle of view (CAMERA), while other aspects such as fuel volume and item are not described here. The main structure of a vehicle is as follows:
The modeling of a car is still rough, but divided into the wheel and the car body. Separating the wheel is mainly to achieve the steering effect of the wheel.
Because the original intention of this game is to achieve a multi-player online game, but in the end failed to achieve the network, it was changed to a single machine. However, the encapsulation is for multiplayer online games.
All vehicles are managed in a unified manner by a class, which uses the singleton design mode. There is another class that encapsulates ogre scenarios and vehicles.
Physicsx, the car body is wrapped by more than a dozen simple patches, and the wheel is the key.
By constructing the layered structure of the wheel, a vehicle consists of a car body and four wheels, and its movement is controlled by the wheel.
The controllable movement of all vehicles (for example, collision is uncontrollable) is driven by the wheel. This is also in line with the physical implementation.
The wheel is implemented mainly through nxwheelshape. The following is an analysis of nxwheelshape.
Nxwheelshape attributes:
RADIUS: range: (0, INF) Wheel radius
Suspensiontravel: range: [0, INF), distance of suspension
Virtual void setlongitudaltireforcefunction (nxtirefunctiondesc tirefunc) = 0
Set the influence of power on positive acceleration.
Virtual void setlateraltireforcefunction (nxtirefunctiondesc tirefunc)
You can set the influence of the power on the lateral acceleration to achieve slide.
Axlespeed: range: (-INF, INF)
Note: nx_wf_axle_speed_override flag must be raised for this to have effect
An overridden axle speed of course renders the axle motor and brake torques ineffective
When setaxlespeed is used, the speed is directly set. This mode is no longer affected by motortorque and braketorque.
Braketorque: range: [0, INF)
Brake moment
Inversewheelmass: sets the influence of power on Acceleration. The greater the effect, the more powerful the effect is.
Motortorque: range: (-INF, INF)
Dynamic Torque to move the vehicle forward
Steerangle: range: (-Pi, Pi) the eccentric angle of the wheel, expressed in radians
Virtual void nxwheeleshape: setsuspension (nxspringdesc spring) [pure virtual]
Related to the connection of other objects
The above section is a summary written previously. Although it is incomplete, I don't want to take it further.
One thing to mention is that although the friction of the wheel, the elasticity coefficient or something (restitution, staticfriction, dynamicfriction) can be set, just like other basic shapes, it does not seem to have any effect, I tried it for a long time. I don't know why. In this way, you can set the brake force to a fixed value to make the vehicle show a certain resistance effect. Only setmotortorque and setbraketorque are able to control the movement speed of a wheel, while setsteerangle affects the wheel angle ), in addition, you can also directly set the forward speed and rotation speed of the wheel. nxwheelshape provides this interface. However, it is recommended that you do not call these two interfaces for the sake of authenticity, because there may be a bunch of formula conversions for implementing the physical effect, but only when the vehicle is initialized or used.
To achieve effects such as slide, you only need to call setlateraltireforcefunction.
In addition, there are still some shortcomings in the use of ready-made nxwheelshape, that is, it is difficult to adjust the feel, and it may be difficult to achieve complex results. I have been calling it for a long time, and I can only do it later.
Physicsx does not need to be processed from the perspective.
The structure of physicsx is basically the same as that of ogre.
How to judge the number of tracks
I don't know how the number of game tracks, such as the need for speeding cars, is different from ours, because it can judge whether the vehicle is going back every moment. We thought about possible methods, such as a certain point in the track, to determine the angle between the vector at the vehicle location and the velocity vector. No.
We use another method that can only judge the number of current circles. This method is very accurate to achieve this. No matter how it is opened, the half of the car body passes through the starting line and then returns anything. This utilizes physicsx trigger.
Place two rectangular nxactor at the starting position of the track, which is very close to each other but is very tall and long with the starting line. The shape attribute of the nxactor is:
Boxdesc. shapeflags | = nx_trigger_enable; // nxboxshapedesc boxdesc;
In this way, any nxactor encountering this physical will trigger an ontrigger process. Here, we only need to define a Class Object (such as mitemtrigger) to accept the trigger event, and this class inherits nxusertriggerreport and implements
Virtual void ontrigger (nxshape & triggershape, nxshape & othershape, nxtriggerflag status) method. Again
Mscene-> setusertriggerreport (mitemtrigger); // nxscene * mscene;
It is possible to achieve this.
Ontrigger is called every time it is triggered. In ontrigger, you can determine whether the object has just entered or left. In fact, there are a total of seven States in the positions of two cubes nxactor (from which one enters the position, although the result location is the same, but it is regarded as different states, in this way, the counting error is returned when half of the vehicle enters the starting line ). The specific status is as follows:
In this way, the transition between States is:
Because only the nxactor can be detected, and the class corresponding to the vehicle (here nxvehicle) is self-encapsulated, it contains an nxactor, so which nxvehicle can take full advantage of void * userdata, a Public Member of nxactor, and point it to its nxvehicle object (this.
Cegui implementation
Reference LZX section:
"The Ogre engine and cegui are used to write basic scenarios and GUI layout.
Cegui reads the configuration file of 2dgui layout, which is written in XML. In this way, the programming and UI design can be relatively separated, so that the program design and UI art design can be better separated. After reading the data, draw it in 3D scenarios ."
This is actually independent from the game process. Due to time constraints, we didn't perform a good encapsulation implementation, just in the class (class cutecarframelistener: Public exampleframelistener, public mousemotionlistener, public mouselistener.
I did not do this, nor did I go into details. This is done after the network fails to be added. Therefore, the network interface is not considered here.
In addition, the implementation of small maps and speedometer is also in this part.
A small map first adds a track chart, obtains the vehicle location from the physical engine, calculates the equivalent position (percentage) on the map, and maps it to the small map.
The speedometer is simpler. You can read the speed and draw a picture.
Implementation of camera from the player perspective
It is already described in vehicle implementation. Here is just an implementation solution.
Create only one camera object. Note that it cannot be attach by multiple scenenode. Therefore, detatch must be used to convert the angle of view. At that time, I had been exploring for some time, but it was all about the basic knowledge of ogre. It was easy to do. Let alone.
Note: In actual vehicle conditions, a person's line of sight is usually a little later than the vehicle turns, and a buffer is added here, that is to say, every time you see something, it is a scene before 30 frames to achieve better results. This is easily achieved through a linked list (array.
In addition, when the vehicle is swinging left and right, the human's perspective will not follow the left and right sides. Although there may be some in reality, it will give people a feeling of shaking too much in the game, here, the left and right swing is removed, that is, the upward vector of camera is always equal to the Y axis, which can be achieved through some mathematical operations. To tell the truth, I have come together and it takes a long time.
Sound implementation
I did not do it either. My classmate LZX did it. Here is a reference:
"The audio module supports 3D and non-3D Playback modes. Considering that reading audio files multiple times during playback increases the CPU usage of the audio module and affects the game, each time an audio file is read to the cache instead of multiple times, read a part each time. ."
The addition of sound has almost no impact on the original program. Because the directsound used is basically independent from the above, LZX encapsulation is also quite good. The thread is automatically enabled during sound playback, which has no effect on other modules of the game.
Network engine addition failed
The original network engine used raknet and encapsulated some things and provided good interfaces. However, because the overall design of the game was inadequate at the beginning, the game framework was designed as an ogre as the main thread, and the network part needs to open up a separate thread for data transmission and processing, if it is in a thread, it will block the thread and cause slow data transmission, or even fail, leading to the inability of the game to continue. due to the time relationship, the Framework Update Time is insufficient, so I had to give up this piece and make it a standalone version.
Because the network engine requires additional threads and buffering, ogre does not provide this function. The best way is to create a main thread and process the Ogre loop as a subthread. However, in this way, the encapsulated system is not supported and changes greatly.CodeThe time is not enough, so you have to give up.
I spent too little energy on the network. The reason is that I didn't pay enough attention to it at the beginning. In fact, we have no experience in programming on the network.
Paste some games, and the artist is still pretty PP
Remarks
After debugging, you can use the log provided by ogre. You cannot debug it step by step. Another good way is to generate the. map file, and then find the specific line of code error in the. map file based on the virtual address error prompt box in windows. This is actually helpful for finding bugs in programs used by players based on error information obtained by players.
From: http://hi.baidu.com/kidcdf/blog/item/ab3e5d16d03f014f20a4e98c.html