Rapport Technique Modifications du code source dues à l'implémentation de la caméra





télécharger 64.39 Kb.
titreRapport Technique Modifications du code source dues à l'implémentation de la caméra
date de publication16.09.2017
taille64.39 Kb.
typeRapport
m.20-bal.com > droit > Rapport
BERNIER Nicolas

GERBER Charles

LE GOFF Erwan

TER

POSITIONNEMENT DE CAMÉRA DANS LES JEUX VIDÉO

- Rapport Technique -

Modifications du code source dues à l'implémentation de la caméra.

Variables globales cf. cube.h.
Notre caméra, que nous pouvons déplacer librement sans nous soucier du player1.

extern dynent *my_camera;

extern int cammode;

enum {CAM_FIXED = 0, CAM_FREE, CAM_OTS, CAM_CUSTOM};
Nous avons par ailleurs ajouté un état « fantôme » (CS_GHOST) aux dynent afin de désactiver certaines contraintes.

enum { CS_ALIVE = 0, CS_DEAD, CS_LAGGED, CS_EDITING, CS_GHOST };
Le mode de caméra, dont la valeur est une des constantes suivantes.

extern int cammode;

enum {CAM_FIXED = 0, CAM_FREE, CAM_OTS, CAM_CUSTOM};
Ces modes sont respectivement :

  • Vue subjective

  • Caméra librement

  • Caméra « over the shoulder »

  • Caméra fixe en un point donné, qui suit les mouvements du joueur


Nous avons créé également 2 modes de positionnement automatique de caméra.

Le premier, commande autocam, permet que la caméra bouge dès que le joueur change de mégacube.

Elle se place dans le coin voulu passé en paramètre.

On change de coin en relançant cette commande avec un autre numéro de coin.

Il ne faut pas oublier de la désactiver par la commande stopautocam si l’on veut un autre angle de vue.

Le deuxième, commande autocam2, permet que la caméra bouge dès que le joueur n’est plus visible par la caméra.

Elle est placée au départ dans le coin voulu du mégacube du joueur.

Ce dernier peut ensuite se déplacer à loisir sans que la caméra ne bouge (elle le suit simplement).

Dès qu’il n’est plus visible, elle se place dans le coin du nouveau mégacube du joueur.

Elle permet une meilleure jouabilité que la précédente.
Pour le mode « over the shoulder » nous avons besoin de définir l'entité sur laquelle est braquée la caméra. Nous utilisons l'index du monstre dans le vecteur des monstres. Cet index prend la valeur -1 pour player1.
// ajout d'un entier représentant l'indice du monstre

// (joueur sinon) suivi en mode CAM_OTS

extern int iplayer_ots ;
// ajout d'un entier permettant de changer le monstre

// suivi par la CAM_OTS

extern int change_ots;
// accès aux monstres

extern dvector monsters;

Le moteur 3D fait appel à une fonction de culling très puissante qui consiste à éliminer les cubes non visibles (occultés). Malheureusement, nous n'avons pas réussi à la maîtriser pour exécuter le culling correctement à partir de la caméra. Nous avons donc passé en variable globale le booléen qui permet de le désactiver.

// accès du booléen gérant l'occlusion

extern bool ocull;
Toutes les variables globales sont initialisées dans clientgame.cpp (lignes 5 à 38).

Fonctions externes cf. protos.h
Les fonctions suivantes doivent-être accessibles à tous les endroits du code. Nous expliquerons leur utilité plus bas.

extern void fixcamerarange();

extern void movecamera(dynent *pl);

Rendu de la scène en 3D
Dans la plupart des cas, afficher la scène à partir de la caméra et non du joueur consiste à remplacer simplement player1 par my_camera.
rendergl.cpp
La fonction transplayer rapporte la scène dans le repère fenêtre en effectuant une composition de translations et de rotation des angles du joueur. C'est la fonction de caméra proprement dite. Nous avons donc remplacé player1 par notre camera my_camera.

void transplayer()

{

glLoadIdentity();

glRotated(my_camera->roll,0.0,0.0,1.0);

glRotated(my_camera->pitch,-1.0,0.0,0.0);

glRotated(my_camera->yaw,0.0,1.0,0.0);
glTranslated(-my_camera->o.x, (my_camera->state==CS_DEAD ? my_camera->eyeheight-0.2f : 0)-my_camera->o.z, -my_camera->o.y);

};
De même, nous avons effectués ces mêmes remplacements dans la fonction principale de rendu 3D à savoir gl_drawframe. Nous avons ajouté un appel vers la fonction cam_on_player qui va calculer la position, les angles et tous les autres paramètres nécessaires de my_camera en fonction de la position de player1. Selon le mode de caméra choisi, on affiche l'arme ou bien un monstre à la position de player1 afin de mieux le visualiser. (lignes 614 à 770)
Au début du fichier rendergl.cpp, nous avons ajouté des nouvelles fonctions gérant les différents modes de caméra :


  • void cam_on_player() (ligne 93) : C'est la fonction qui détermine la position de la caméra en fonction du mode choisi. Elle est appelée avant tout traitement de rendu et à chaque image.

  • void ots(dynent *player_ots) (ligne 32) : Cette fonction calcule pour chaque image la position de la caméra à l'épaule de la dynent passée en paramètre. La position optimale est calculée en prenant compte les contraintes de l'environnement.

  • Les fonctions suivantes permettent de changer de mode de caméra, de les initialiser ainsi que les contrôler.

    • void fixedcam() (ligne 171)

    • void freecam() (ligne 182)

    • void camots() (ligne 196)

    • void changeots() (ligne 204)

    • void customcam(int x, int y, int z) (ligne 213)

    • void coincam(int numcoin) (ligne 231)

    • void autocam(int numcoin) (ligne 244)

    • void autocam2(int numcoin) (ligne 257)

    • void stopautocam2() (ligne 272)

    • void stopautocam() (ligne 281)

    • void lockcam() (ligne 289)


D'autres remplacements de player1 par my_camera ont été effectués dans les fichiers suivants :

  • rendermd2.cpp (lignes 246 à 255)

  • renderparticles.cpp (lignes 51 à 60)

  • worldocull.cpp (lignes 24 à 41)

  • worldrender.cpp (lignes 20 à 31, 52 à 62, 82 à 92 et 158 à 171)


Contrôle de la caméra en utilisant les contrôles du joueur (clavier et souris) (mode caméra libre).
Le mode caméra libre nécessite de rediriger les contrôles de player1 vers my_camera. Ceci est fait dans le fichier clientgame.cpp, entre les lignes 356 et 364 pour les touches de direction du clavier et les lignes 429 à 257 pour la souris. Par ailleurs, les fonctions « sauter » et « tirer » sont désactivées en mode caméra libre (respectivement lignes 390 et 376). Comme pour player1 en mode « vue subjective », des butées ont été définies pour la caméra afin de corriger les valeurs de caméra incorrecte. Ceci est fait par la fonction fixcamerarange (lignes 415 à 127) qui n'est qu'une pâle copie de la fonction fixplayer1range.

Enfin, la caméra peut-être déplacée (lignes 272 à 292) en appelant la fonction movecamera de la source physics.cpp (lignes 221 à 319), fonction créée à partir de moveplayer.
Contraintes de positionnement, collisions
La seule contrainte de positionnement de caméra que nous avons posée est que la caméra ne doit jamais être placée à l'intérieur d'un obstacle (monstre, mur...). Le positionnement optimal en mode « over the shoulder » est calculé dans la fonction ots de rendergl.cpp évoquée précédemment (ligne 32). En mode « caméra libre », la contrainte est gérée par la fonction movecamera de physics.cpp (ligne 229).
Le test de collision est effectué par la fonction collide dans physics.cpp (ligne 62). La fonction renvoie vrai si la dynent passée en paramètre n'est en collision avec aucun obstacle. Cette fonction prend en compte les entités présentes sur la map. Selon le mode de caméra choisi, elle ne doit pas prendre toujours en compte les mêmes. Ainsi, player1 ne doit pas être pris en compte en mode caméra libre ou en over the shoulder sur lui-même (lignes 130 à 144). Il en est de même pour le monstre actif en mode over the shoulder (lignes 150 à 161). Enfin, la taille des monstres est variable et il est nécessaire de la prendre en compte par rapport à la hauteur au plafond (lignes 74 à 83).

Modifications du code source dues à l'implémentation des mégacubes.
Il n’y a pratiquement pas de modifications du code original : tout le code créé pour gérer les mégacubes est contenu des les fichiers commençant par « ter_ » (ter_cube.h , ter_cube.cpp, ter_main.cpp, ter_megacube.h, ter_megacube.cpp). Le code étant bien commenté, nous vous fournissons le listing en annexe. Comme cela vous pourrez voir les méthodes de chaque classe, ainsi que leur rôle.
L’appel de notre programme est situé dans le fichier « worldio.cpp » à la ligne 490 (à peu près).


Les cubes.
Le jeu est basé sur un empilement de petits cubes (d’où son nom).

Les cubes sont définis par la structure sqr du fichier cube.h :
struct sqr

{

uchar type; // one of the above

char floor, ceil; // height, in cubes

uchar wtex, ftex, ctex; // wall/floor/ceil texture ids

uchar r, g, b; // light value at upper left vertex

uchar vdelta; // vertex delta, used for heightfield cubes

char defer; // used in mipmapping, when true this cube is not a perfect mip

char occluded; // true when occluded

uchar utex; // upper wall tex id

uchar tag; // used by triggers

};
Ils ont donc un type, un plafond (ceil), un plancher (floor), 3 textures (côté  wtex, haut  ctex, bas  ftex) et d’autres champs.
Leur type est l’un des suivants :
enum // block types, order matters!

{

SOLID = 0, // entirely solid cube [only specifies wtex]

CORNER, // half full corner of a wall

FHF, // floor heightfield using neighbour vdelta values

CHF, // idem ceiling

SPACE, // entirely empty cube

SEMISOLID, // generated by mipmapping

MAXTYPE

};
 type SOLID : les gros murs « porteurs »de la map

 type CORNER : coin des murs

 type FHF : les obliques au sol

 type CHF : les obliques au plafond

 type SEMISOLID : les murs qui sont loin (type utilisé lors du mipmapping)

 type SPACE : cube vide (espace)

Le joueur et les monstres.


Ils sont définis tous les deux par la structure dynent (dynamic entity) dans le fichier cube.h.

struct dynent // players & monsters

{

vec o, vel; // origin, velocity

float yaw, pitch, roll; // used as vec in one place

float maxspeed; // cubes per second, 24 for player

bool outsidemap; // from his eyes

bool inwater;

bool onfloor, jumpnext;

int move, strafe;

bool k_left, k_right, k_up, k_down; // see input code

int timeinair; // used for fake gravity

float radius, eyeheight, aboveeye; // bounding box size

int lastupdate, plag, ping;

int lifesequence; // sequence id for each respawn,

// used in damage test

int state; // one of CS_* below

int frags;

int health, armour, armourtype, quadmillis;

int gunselect, gunwait;

int lastaction, lastattackgun, lastmove;

bool attacking;

int ammo[NUMGUNS];

int monsterstate; // one of M_* below, M_NONE means human

int mtype; // see monster.cpp

dynent *enemy; // monster wants to kill this entity

float targetyaw; // monster wants to look in this direction

bool blocked, moving; // used by physics to signal ai

int trigger; // millis at which transition to another

// monsterstate takes place

vec attacktarget; // delayed attacks

int anger; // how many times already hit by

// fellow monster

string name, team;

};
A tout moment on peut accéder aux joueurs et aux monstres par des variables globales players et monsters qui sont des listes de personnages.

En mode single player, on accède directement aux informations du joueur par la variable player1.
Leurs coordonnées se trouvent dans le champ o (origin) de la structure.

Ce champ est un vecteur de 3 coordonnées (x,y,z) qui situent le personnage dans l'espace.
Un personnage est orienté selon 3 angles yaw, pitch, roll.
Chaque personnage a un état (champ state) qui appartient à la liste suivante :

enum { CS_ALIVE = 0, CS_DEAD, CS_LAGGED, CS_EDITING, CS_GHOST };

Nous avons ajouté le mode CS_GHOST pour exploiter dynent pour notre caméra.
Les monstres ont, quant à eux, un état supplémentaire monsterstate qui peut être l'un des suivants :

enum { M_NONE = 0, M_SEARCH, M_HOME, M_ATTACKING, M_PAIN, M_SLEEP, M_AIMING };
M_NONE indique que le joueur est humain (n'est donc pas un monstre).

Les monstres peuvent être actifs ou non. Seuls les actifs nous intéressent : leur état monsterstate est différent de M_SLEEP.
Pour plus de renseignements sur les monstres, il faut aller voir le fichier monster.cpp.
Nous avons créé une fonction monsterincrosshair() qui permet d’obtenir le nom du monstre visé par le curseur du joueur (cf. fichier weapon.cpp).
Les coordonnées de ce qui est pointé par le viseur du joueur sont données par le vecteur worldpos. Les murs.
Les gros murs porteurs de la map sont les cubes dont le type est SOLID.
Les murs sont créés avec la fonction render_wall du fichier worldrender.cpp.
Cette fonction est appelée par la fonction render_seg_new (dans le même fichier).
Il y a une distinction entre les murs dits « normaux » et les autres.
Ces murs « normaux » sont tous les murs qui ne sont pas obliques.
La fonction effectue, au préalable, des études de cas permettant de construire les murs diagonaux.


Les maps.
Le chargement des maps s'effectue dans le fichier worldio.cpp.
Certains cubes n'apparaissaient pas dans le fichier map origine (fichier .cgz) mais sont recopiés en mémoire car ils apparaissent dans le jeu. C'est le cas notamment pour les cubes qui bordent la carte et qui sont de type SOLID.
Il existe une variable world qui est stocke tous les cubes du jeu.

Cette variable est une matrice carrée car toutes les map du jeu sont carrées.

Elle est codée sous la forme d'un simple tableau.

On accède à la ligne suivante de la matrice en additionnant l'indice à la taille de la matrice.
Illustration :


La valeur d'un côté d'une map est une puissance de 2 et commence à 64 (puis 128...).

Cette taille est donnée par la variable ssize.

La matrice world est une matrice ssize * ssize.

Il y a par conséquent ssize² cubes dans la map.

Cette valeur est donnée par la variable cubicsize.

Les coordonnées des cubes sont données par le couple (x,y) qui est leur emplacement dans la matrice world.

On peut y accéder directement grâce à la fonction S(x,y).

Leur hauteur (coordonnée z) n'est pas explicitée clairement.

Le programme gère plutôt 2 hauteurs : le haut du cube (ceil) et le bas (floor).

Les cubes de type SOLID sont des cubes qui partent du sol de la map et qui vont jusqu'à son plafond.

Les entités.
 Description des entités par les structures entity et persistent_entity dans cube.h.

Une entité peut être aussi bien un élément du décor (type MAPMODEL) que les points de départ des joueurs et des monstres, la position des lumières, celle des armes, des munitions...

Une entité est définie par ses coordonnées dans la map, un type et 4 attributs qui diffèrent selon l'entité.

Une entité n'est pas considérée comme un cube à part entière.

Toutes les entités du jeu sont stockées dans un tableau ents.

Les entités à prendre surtout en compte sont les MAPMODEL.

Elles peuvent se retrouver séparément : leur attribut 2 représente un indice qui permet d'avoir accès aux informations concernant le MAPMODEL en question.

Ces informations sont données par la fonction getmminfo(int i) du fichier rendermd2.cpp et sont stockés dans une structure mapmodelinfo.

Liste des commandes que nous avons créés.
Nous avons créé plusieurs commandes.

Pour taper une commande, taper ‘T’ dans le jeu puis « /nom_commande ».
fixedcam  met la caméra dans le joueur1 (vue normale)
freecam  active le mode fantôme qui permet de déplacer la caméra avec les flèches et la souris et non le joueur.
customcam x y z  place la caméra aux coordonnées (x,y,z)
lockcam  fixe la caméra à la position du joueur1. On déplace ensuite le joueur sans que la caméra ne bouge ni le suive.
showmegacube  affiche les bords du mégacube du joueur en vert. Si le mégacube a des morceaux, ils sont affichés en orange. Rappeler la commande désactive l’affichage.
camots  place la caméra en over the shoulder sur le joueur1.
changeots  place la caméra en over the shoulder sur les monstres actifs. Rappeler la commande change de monstre ou revient sur le joueur1.
coincam coin place la caméra dans le coin voulu du mégacube du joueur
autocam coin  lance la première version de changement automatique de positionnement de caméra décrite plus haut.
stopautocam  arrêt de la commande précédente.
autocam2 coin  lance la deuxième version de changement automatique de positionnement de caméra décrite plus haut.
stopautocam2  arrêt de la commande précédente.
affichedetails  mode d’affichage détaillé. Ces affichages nous ont servi de base à la compréhension. Nous les avons laissés au cas où. On revient en mode normal en rappelant cette commande.

similaire:

Rapport Technique Modifications du code source dues à l\Bibliographie Annexe 1 : Code source Méthode Des Segments Annexe...
«monstres» dont on ne parlait qu’à couvert avant de les maîtriser réellement. IL en a été ainsi chez les pythagoriciens avec l’apparition...

Rapport Technique Modifications du code source dues à l\Auteur
...

Rapport Technique Modifications du code source dues à l\Bronchite aiguë: épisode d'inflammation aiguë des voies respiratoires,...

Rapport Technique Modifications du code source dues à l\Rapport des commissaires aux comptes, établi en application de l'article...

Rapport Technique Modifications du code source dues à l\Source : kiwimage com Source : nasa matériels disponibles

Rapport Technique Modifications du code source dues à l\Dispositions relatives au commerce de l’energie
«biens énergétiques»: le gaz naturel (code sh 27. 11), l'électricité (code sh 27. 16), le pétrole brut (code sh 27. 09-27. 10)

Rapport Technique Modifications du code source dues à l\Rapport Technique

Rapport Technique Modifications du code source dues à l\Rapport d’activités des epm
«code unique», recommandé par le ministère de la santé, les epm ont attribué à chaque ps un code, et noté tous les informations nécessaires...

Rapport Technique Modifications du code source dues à l\Animatrice Manager Cyber-base de la Nièvre
«à sources ouvertes». Toutefois, la notion formelle de logiciel Open Source telle qu'elle est définie par l'Open Source Initiative...

Rapport Technique Modifications du code source dues à l\Rapport technique d’execution janvier 2005 Introduction : Le projet...





Tous droits réservés. Copyright © 2016
contacts
m.20-bal.com