|
A database in the middle of project |
Games videos manipulate a big quantity of data it would be only to load models, to manage the statistics of entities... It is therefore necessary to have recourse to databases to stock this information. The heart of
Singularity is a database Access exported in form of text files with
délimiteurs. There is not directly module to manage bases Access and
SQL under Dark Basic Pro. Tables are therefore loaded in pictures which are then exploited in the programme.
To construct a database rigorously is not always easy. How to avoid redundancy at the farthest while keeping some unit in information? It is the challenge of the programmer... The database of
Singularity is composed of 42 tables, what represents 270 fields! Let us see how is structured database:
| NAME |
NUMBER |
FONTION |
| MEDIA |
5 |
Resource management (3D, 2D, sounds). |
| DB |
20 |
The fixed data of game represent. They are not changed in game. It is notably about statistics of entities, of weapon but also messages, texts, positions of interface... |
| INFORMATION |
6 |
These tables stock the fluctuating data of game which vary according to the player (life, ammunition, state of game). |
| INIT |
11 |
It is about load tables which configurent game only in every of the beginning of part. They make link between media and fixed data. |
This strict cutting up of data has many advantages:
- There is not confusion between resources and pure data.
- Stable and fluctuating data are separated. So to safeguard a part returns to keep only the fluctuating tables (INFORMATION). to Publish a patch, it is only to update the fixed tables (DB) without risk of corrupting the profile of the player.
The relational diagramme of database is available below. The entirety of relations was not shown for more legibility.
Click on the picture to show it in full screen
|
Include database into the engine of Dark Basic Pro |
The choice came on the export of database in form of text files. A simple macro in
Access allows to update fast the files of game. But how to treat these data without requests SQL? First of all, every table is entirely loaded in a classical picture composed of structures (=types user). Here is for example, the transfer to the memory of the file concerning entities:
REM DEFINITION OF DATABASE: INFO_ENTITES
REM-----------------------------------------------
FUNCTION BASE_DE_DONNEES_INFO_ENTITES (Ligne$ ace G-string)
place IDEM, Life, ID_PROJECTILE, Ammunition ace integer
IDEM =Val (Extraction (Ligne$,1))
Life =Val (Extraction (Ligne$,2))
ID_PROJECTILE =VAL (Extraction (Ligne$,3))
Ammunition =Val (Extraction (Ligne$,4))
ARRAY INSERT AT BOTTOM BD_INFO_ENTITES ()
BD_INFO_ENTITES ().ID=ID
BD_INFO_ENTITES ().Vie=Vie
BD_INFO_ENTITES ().ID_Projectile=ID_Projectile
BD_INFO_ENTITES ().Munitions=Munitions
BD_INFO_ENTITES ().Action = ""
BD_INFO_ENTITES ().Animation = ""
BD_INFO_ENTITES ().Delai=0
EndFunction
|
Once all tables are loaded, another problem settles. How to achieve a recording fast (line of the table) while there are several hundred of lines? A simple research loop would be too heavy to manage given the consequent number of information to harvest every other minute game. A pressure on the filling of tables was therefore fixed. Every recording is therefore identified (primary key) by a number pointing its indication out exactly in the corresponding picture. So if they want to know the life of the entity identified by the number 23, it is enough to position in the indication 23 of the picture of entities. It is therefore possible to qualify this maneuver of direct access. The navigation in database is rather easy now while knowing that the joint between tables was avoided at the farthest.
|
The organisation of project under Dark Basic Pro |
Some rigour at the level of files, names, of the way to program is necessary to make easier service tasks. In very constant, possible measure is defined in a variable at the beginning of programme. This allows to change fast data in one and single place of code. Here is an extract of the used constants:
Constants. Camera. Vitesse_Depl=10
Constants. Camera. Vitesse_Angle=0.3
Constants. Camera. Angle_X_Min=60
Constants. Camera. Angle_X_Max=300
Player. Camera. Active=true
Player. Miscellaneouses. Saut_Delai=1000
Player. Miscellaneouses. Saut_Hauteur=200
Constants. Portee. ObjAnim=500
Constants. Portee. Actions=600
Constants. Portee. Objets=500
Constants. Sounds. Portee=5000
Constants. Sounds. ID_MUSIQUE =-1
Constants. Sounds. Indice_Temp=1
Constantes.Entites.Delai_Suppression=10000
Systeme. Stopwatch. FPS_BASE=50
Systeme.Environnement.Champ_Vision_Pres=1
Systeme.Environnement.Champ_Vision_Loin=3000
Systeme.Environnement.Lumiere_Ambiante=60
Systeme.Environnement.Gravite_Physique_X=0
Systeme. Environment. Gravite_Entites=30
Systeme. Environment. Rayon_AI=80
Systeme. Keys. Avancer=200
Systeme. Keys. Reculer=208
Systeme. Keys. Gauche=203
Systeme. Keys. Droite=205
|
Project was divided into thematic files containing each group of functions. The orientated coding objects not being possible, it was necessary to adopt a functional approach in modules. 28 thematic modules were created:
ACTIONS, HAVE, ANIMATIONS, AUDIO, BILLBOARDING, CAMERA,
CHAINS, LOAD, COLLISIONS, STATEMENT, DIALOGUE,
MISCELLANEOUSES, SCREEN, ENTITES_AI, EVENTS, CAST IRON, CORRELATIONS,
LISTBOX, MATHS, OBJECTS, OBJETS_ANIMES, PERIPHERALS, PHYSICAL APPEARANCE,
PROJECTILES, SCRIPTS, SOURCE, SPRITES, SYSTEM
|
Alone SCRIPTS module is entirely dependent on game since it takes care of the
scénaristique holding of game. Other modules were create and tested
séparemment. They are entirely
réutilisables and their update is very easy. Here is for example an extract of the module linked to mathematics.
REM OUTDISTANCES BETWEEN TWO POINTS
REM--------------------------
FUNCTION MATH_DISTANCE_2_POINTS (X1#, Y1#, Z1#, X2#, Y2#, Z2# float ace, Dimension ace integer)
place X#, Y#, Z#, Distance# float ace
Yew tree Dimension=3
vecteur=make vector3 (1)
X#=X1#-X2#
Y#=Y1#-Y2#
Z#=Z1#-Z2#
jeu vector3 1,X#,Y#,Z#
Distance#=length VECTOR3 (1)
EndIf
Yew tree Dimension=2
vecteur=make vector2 (1)
X#=X1#-X2#
Z#=Z1#-Z2#
jeu vector2 1,X#,Z#
Distance#=length VECTOR2 (1)
EndIf
EndFunction Distance#
|
In a game, an "infinite" main loop manages permanently the holding of the part. The more length of execution of this one is quick, the more game is fluid. The optimisation of treatments performed am therefore primordial in a game. Here is the contents of the main loop of
Singularity. To note that only calls of functions of update of every module is performed. Treatments under the same theme are so regrouped.
Do
SYSTEME_TEMPS_MAJ ()
ACTIONS_CLAVIER ()
ACTIONS_SOURIS ()
OBJETS_ANIMES_MAJ ()
SCRIPTS_TRIGGERS ()
TRIGGERS_MAJ ()
RunCollisionPRO () `COLLISIONS
PERIPHERIQUES_MAJ ()
CAMERA_MAJ () `CAMERA
COLLISIONS_MAJ ()
PROJECTILES_MAJ ()
ENTITES_AI_MAJ ()
ECRAN_INTERFACE ()
ECRAN_INFORMATIONS ()
AUDIO_MAJ () `AUDIO
BILLBOARDS_MAJ ()
ANIMATIONS_MAJ ()
HAVE update `IA
phy update `PHYSIQUE
SCRIPTS_SHADER_RENDU ()
sync `RENDU
Loop
|
A good management of collisions is primordial in a game there 3D of type FPS. I turned to the use of a
plugin NuclearGloryCollision for time saving in a domain which I did not control. This tool allows to manage easily collisions of two types:
- Ellipsoid: the model 3D is roughly represented by one ellipsoid. Collisions are so easier to calculate because the model has no complex form. Nevertheless precision is collisions am of course lesser. This was used for all entities including the hero and projectiles.
- Mesh (mesh size): the precise form of the object is taken into account. It is about a collision detection in the polygon near. This is much more gourmand than simple one ellipsoid but precision is augmented. This mode of collision for the decor is generally reserved.
To differentiate the different elements entered in the engine, different types of groups were defined, each able
to intéragir the one with other one:
TYPE_DECOR
TYPE_OBJANIM
TYPE_ENTITE
TYPE_JOUEUR
TYPE_ACTION
TYPE_ARME
TYPE_OBJET
TYPE_PROJECTILE
TYPE_PHYSIQUE
TYPE_BILLBOARD
|
The collision of projectiles is real what means that an impact takes place when the projectile and its target got into contact. It is not about a collision calculated by the method of
"Raycasting" which consists in simulating a collision between a starting point and arriving point at given instant.
The management of physics is entirely assured by the
plugin DarkPhysics. It is about a collision engine richer than precedent. He allows to manage forms of collision more adapted (cube, sphere, ground, mesh size). To avoid blocking memory with objects already in the collision
NuclearGlory plugin, alone decor and objects says "physical" are loaded.
A problem settles when in the simultaneous functioning of the physical engine and of the collision system. How the projectiles of weapon belonging only to the collision system will be able
to intéragir and move the physical objects? During a collision between a projectile and one object, a force to this object is manually applied. The engine undertakes then to manage corresponding displacements. Here is routine made responsible for making announce two
plugins. They recover at first the co-ordinates of collisions with which they form a vector representing the trajectory of the projectile. After normalisation, it is possible to calculate force to be applied to every axle to reflect impact.
ID_COLLISION=COLLISIONHITOBJPRO (IDEM, Index_Collision)
Collision=CollisionHitTypePro (IDEM, Index_Collision)
Collision_X#=CollisionHitPointPro (IDEM, Index_Collision, 1)
Collision_Y#=CollisionHitPointPro (IDEM, Index_Collision, 2)
Collision_Z#=CollisionHitPointPro (IDEM, Index_Collision, 3)
Pos_X#=CollisionHitPosPro (IDEM, Index_Collision, 1)
Pos_Y#=CollisionHitPosPro (IDEM, Index_Collision, 2)
Pos_Z#=CollisionHitPosPro (IDEM, Index_Collision, 3)
Yew tree Collision=TYPE_PHYSIQUE
Force_Physique#=BD_Projectiles (Index).Force_Physique
temp = make vector3 (1)
jeu vector3 1,Collision_X#-Source_X#,Collision_Y#-Source_Y#, Collision_Z#-Source_Z#
normalise vector3 1,1
phy add rigid body forces ID_COLLISION, x vector3 (1) *Force_Physique#,y vector3 (1) *Force_Physique#,
z vector3 (1) *Force_Physique#, Collision_X#, Collision_Y#, Collision_Z#,1
EndIf
|
A
plugin new,
Dark HAVE, was used to make easier the installation of an artificial intelligence. A good IA is entirely based on an efficient
pathfinding (=recherche of the shortest way between two points). The
plugin uses algorithm A* to calculate a trajectory. His strong point is the way it determines the outlines of the decor and the passage points. Indeed, he calculates collisions between the decor and a horizontal plan to generate borders of level and
waypoints. Then the whole panoply of actions can be developed (actions defined for entities, attitudes and behaviours). The weakness of the
plugin is however based on the single management of environment in two dimensions. To define several floors or levels, it is necessary to point out manually in what game plan is necessary be entity (of container system).
|
The billboarding or the simulation of the 3D with the 2D |
The method of the
billboarding is still very fluently used in games videos (Command And Conquer 3 for example). It consists in showing an element there 2D which is always orientated towards the camera. An effect of volume is so simulated since the object swivels at the same time as the camera. It is so less fond of good food to manage a texture enlivened there 2D as its equivalent there 3D. Phantasm is however less strong when they are too much near the object in question. That is why they reserve that this technology generally for the distant elements which do not need a model in high resolution (trees in the distance). Explosions of projectiles, fire are very often simulated by the method of the
billboarding.
Let us see his installation under Dark Basic Pro. There are 4 fundamental stages:
- Creation of an even (=objet 3D without thickness)
- Application of a texture with effect of transparency (Ghost)
- Direction of the even towards the camera
- Animation of texture if necessary
To note that the direction of the object towards the camera is facultative if they want to simulate stagnant objects (rain, not).
`Création
even make object ID_OBJET, Breadth, Height
object ID_OBJET position, Pos_X#, Pos_Y#, Pos_Z#
rotate object ID_OBJET, Angle_X#, Angle_Y#, Angle_Z#
ID_OBJET, 0 are ghost object
`Boucle main
object ID_OBJET, ID_IMAGE texture
OBJECT ID_OBJET, Camera. Pos_X, object position Y (ID_Objet), Player. Camera. Pos_Z
|
|
Sounds in an environment there 3D |
To augment the realism of a game, sound effects have a primordial role. So that the immersion is complete, the volume of sounds and the sharing out on surrounding walls is entirely defined. Under Dark Basic Pro, the volume of the sound is determined according to a report between the position of the player and that of the sound. A so calculated percentage points out the volume of the sound.
FUNCTION AUDIO_SON_VOLUME (ID_Son ace integer, X#, Z# ace float)
place Volume_Min, Volume_Max ace integer
place Distance#, Result# float ace
Distance#=MATH_Distance_2_points (Player. Camera. Pos_X,-1, Player. Camera. Pos_Z, X#,-1, Z#,2)
Yew tree Distance#<=Constantes.Sons.Portee
Volume_Min=BD_Sons (ID_Son).Volume_Min
Volume_Max=BD_Sons (ID_Son).Volume_Max
Result#=1 - (Distance#/Constantes.Sons.Portee)
Result#=Result#* (Volume_Max-Volume_Min) +Volume_Min
Else
Result#=0
EndIf
EndFunction Result#
|
The calculation of the section, that is to say the sharing out of the sound on the left or right surrounding wall is more complex. Indeed, it is above all a question of determining if the sound was launched to the left or the right of the player. For it a calculation
trigonométrique allows to determine the angle between the sound and the player. A report in form of percentage is then calculated to divide the sound on every surrounding wall.
FUNCTION MATH_ANGLEY (X#, Z# ace float)
place Angle# float ace
Yew tree X#>Joueur.Camera.Pos_X and Z#>Joueur.Camera.Pos_Z then
Angle#=abs (atan ((X#-Joueur.Camera.Pos_X) / (Z#-Joueur.Camera.Pos_Z)))
Yew tree X#>Joueur.Camera.Pos_X and Z#<Joueur.Camera.Pos_Z then
Angle#=abs (atan ((Z#-Joueur.Camera.Pos_Z) / (X#-Joueur.Camera.Pos_X))) +90
Yew tree X#<Joueur.Camera.Pos_X and Z#<Joueur.Camera.Pos_Z then
Angle#=abs (atan ((X#-Joueur.Camera.Pos_X) / (Z#-Joueur.Camera.Pos_Z))) +180
Yew tree X#<Joueur.Camera.Pos_X and Z#>Joueur.Camera.Pos_Z then
Angle#=abs (atan ((Z#-Joueur.Camera.Pos_Z) / (X#-Joueur.Camera.Pos_X))) +270
Angle#=wrapvalue (Angle#-Joueur.Camera.Angle_Y)
EndFunction Angle#
FUNCTION AUDIO_SON_PAN (X#, Z# ace float)
place temp#, Result#, Angle# float ace
Angle#=MATH_AngleY (X#, Z#)
`Enceinte left
Yew tree Angle#<=360 and Angle#>=180
temp#=abs (Angle#-270)
Result#= (temp#/90)-1
Else
`Enceinte right
temp#=abs (Angle#-90)
Result#= (90-temp#)/90
EndIf
EndFunction Result#
|
With Dark Basic Pro, it is impossible to load new resources dynamically. The not being available
multi-threading. In the case of sounds, this means that it is necessary to load beforehand a number predefined by sound effects. In other words, it is necessary to load for example 5 noise of shooting of gun. But how make when more than 5 entities pull at the same time? Smartness has consist in maintaining that major sound differentiation between 5, 6 or 7 simultaneous sounds would not be made. As soon as the maximum sound number is attained and as soon as a new individual launches a new sound, that having the weakest volume is stopped to be to redeploy in the new individual. A weaker sound is therefore replaced with a stronger sound, the phantasm of the number is therefore improved!
|
The speed of execution of game - Timer Based Movement |
To throw a game consists in carrying out always an "infinite" main loop which performs all treatments. The speed of execution of this loop depends entirely on the computer which carries it out (=sa shape). In other words, on a powerful computer the loop will comply more quickly than on a normal computer. This poses a major problem: that of the speed of game in full part. The character of will move more quickly, animations will be speeded up in short, it is necessary to set up a mechanism harmonising the speed of execution on all machines. The number of loops carried out a second is what is fluently called
FPS: the number of frames per second.
Smartness consists in calculating an acceleration or slowing down coefficient to compensate for the speed of movements in game. Indeed, on a normal computer, coefficient will be 100 %. On a twice as quick PC, coefficient will be only 50 % to reduce by half the speed of movements. This coefficient is determined according to the length of execution of a main loop. It is applied as well to the movements of entities, of camera as to animations. This method has however tendency to cause starts when the number of frames per second is very low since the compensation of movement is very important.
FUNCTION SYSTEME_TEMPS_MAJ ()
Systeme. Stopwatch. Temps=Timer ()
Systeme.Chrono.Coefficient=Systeme.Chrono.FPS_Base*
(Systeme.Chrono.Temps-Systeme.Chrono.Temps_Precedent)/1000.0
Systeme.Chrono.Temps_Precedent=Systeme.Chrono.Temps
`Formule:
` FPS_REEL = (Temps_Actuel-Temps_Precedent) / 1000.0
` Coef = FPS_BASE / FPS_REEL
` ==> Coef = [FPS_BASE * (Temps_Actuel-Temps_Precedent)] / 1000.0
EndFunction
|
|
Interface and management of resolutions |
The management of a game interface is more complex than he parried there. Indeed, main preoccupation is born when it is a question of developing a game can imports the resolution of the screen. How to position elements? How to adapt their dimensions?
In
Singularity, the positioning of elements is relating. This means that he is calculated according to the size of the screen, of the position of another element or by an absolute value according to following expression:
POSITION (calculated in the load) = % SCREEN [+/-BREADTH Of AN ELEMENT] [+/-VALUE FIXED]
In that way he resolution and even am very easy to position an object about is to write the text in a graphic zone envisaged with this effect. The management of the size of pictures was not envisaged because it was not necessary for this stadium. Different resolutions interfaces would have been able to be used rather than of
agrossir or reduce elements.
The player must also
intéragir with interface. A button remains a simple graphic element which has no properties which it would be possible to know it during the creation of a software. He is not our responsibility to implement his behaviour. To simulate different states (not clicked), enlivened
sprites was used. Passage from a
frame to the other one taking place in every click or support.
Main difficulty was to identify a click apparently. Indeed, during the same click, Dark Basic Pro launches event in regular interval "click ". It is therefore impossible to know precisely when starts or ends the click. An individual function was therefore necessary:
FUNCTION PERIPHERIQUES_MAJ_SOURIS ()
`Systeme. Mouse. Clic_Actuel <= return the uninterrupted click
`Systeme. Mouse. Clic_Unique <= return an unique click
Systeme.Souris.Clic_Precedent=Systeme.Souris.Clic_Actuel
Systeme. Mouse. Clic_Actuel=MouseClick ()
Systeme. Mouse. Clic_Unique=0
Yew tree Systeme. Mouse. Clic_Actuel <> 0 and Systeme.Souris.Clic_Actuel<>Systeme.Souris.Clic_Precedent
Systeme.Souris.Clic_Unique=Systeme.Souris.Clic_Actuel
EndIf
EndFunction
|