skizzle/docs/rapports/rapport-initial-delabre/parts/ptf.tex

309 lines
13 KiB
TeX
Raw Normal View History

\chapter{Jeu de plateformes coopératif}
Les jeux de plateformes sont un des premiers genres
à avoir émergé dans le monde du jeu vidéo. Ils consistent
à faire progresser un personnage en le faisant aller
de plateforme en plateforme, d'où leur nom.
Le troisième jeu étudié a un principe original, inspiré
des jeux de plateformes, de coopération et de réflexion. Il
s'agira pour deux joueurs de faire traverser deux balles
aimantées à travers un niveau, certains éléments du décor
étant eux aussi aimantés.
La conception du jeu s'appuiera sur cet élément
physique pour proposer des niveaux sous forme de casse-têtes,
dans lesquels les deux participants devront s'entraider et
réfléchir pour parvenir à la fin.
\section{Principes}
Deux joueurs doivent s'entraider pour faire avancer leur balle à travers
des niveaux. Les joueurs exploitent pour ce faire les mécanismes
physiques définis dans la section \ref{section:ptf-joueurs}.
Le jeu est constitué d'une suite de niveaux, chaque niveau
étant une grille de blocs en deux dimensions. Ces grilles sont
définies en avance par le programmeur. Les blocs interagissent
avec les balles comme défini dans les sections \ref{section:ptf-joueurs}
et \ref{section:ptf-blocs}.
Les joueurs valident un niveau en faisant parvenir toutes les
balles dans une zone d'arrivée prédéfinie. Ils passent
ainsi au niveau suivant. Le but du jeu est de terminer tous
les niveaux.
\subsection{Joueurs}
\label{section:ptf-joueurs}
Les deux joueurs contrôlent chacun une balle. Ces balles ont pour
propriétés leur position dans le plan, leur vitesse et leur charge
électrique. Les balles évoluent par interactions
avec le joueur et par interactions physiques.
Un joueur peut interagir avec sa balle de trois manières~:
il peut lui donner de la vitesse vers la gauche de la fenêtre,
la droite de la fenêtre, ou inverser la polarité de la balle.
Le joueur ne peut pas faire « sauter » sa balle.
L'évolution des balles, en dehors du contrôle des joueurs, est
conditionnée par les phénomènes physiques suivants~:
\begin{itemize}
\item une force de gravité qui agit en tout point et attire
les balles vers le bas, le haut, la gauche ou la droite de la
fenêtre. L'orientation de cette force peut être modifiée par les
actions d'une balle en cours de jeu~;
\item une force de réaction qui agit de telle sorte
que les balles ne puissent pas traverser les blocs~;
\item des forces de frottements lorsque la balle se situe
au contact d'un bloc. L'intensité de cette force varie
en fonction des types de blocs~;
\item une force d'interaction coulombienne entre les éléments
du jeu qui sont polarisés (c'est-à-dire les balles et
certains blocs tels que définis en section \ref{section:ptf-blocs}).
\end{itemize}
\subsection{Caméra}
À tout moment les deux balles peuvent se situer n'importe où dans le
niveau. Il faut toutefois faire en sorte qu'elles soient toutes deux
visibles à tout moment.
Pour ce faire, la caméra est centrée sur la position moyenne
des deux balles si celles-ci sont suffisament proches. Sinon,
l'écran est divisé en deux et chaque partie est centrée sur chacune
des balles.
\subsection{Blocs}
\label{section:ptf-blocs}
Le niveau est une grille de blocs. Les blocs possèdent
une position sur la grille déterminée par une paire d'entiers et
une charge électrique qui peut être annulée pour que le bloc
n'attire aucun objet. Certains blocs peuvent modifier le sens
de la gravité lorsqu'une balle rentre en collision avec eux.
Enfin, les blocs sont statiques et ne sont pas soumis
à la physique du jeu.
\section{Modélisation}
Les balles sont modélisées par une classe \texttt{Ball}. Cette
classe est dotée des propriétés \texttt{position},
\texttt{velocity}, \texttt{mass} et \texttt{charge}.
Le vecteur \texttt{position} représente la position de la balle
dans le plan. Le vecteur \texttt{velocity} représente la
vitesse de la balle. Le flottant \texttt{mass} représente la masse
de la balle, qui sera utilisée dans le calcul de l'accélération.
Enfin, le flottant \texttt{charge} représente sa charge électrique.
Les blocs sont modélisés par une classe \texttt{Block} munie
des propriétés \texttt{position} et \texttt{charge}
qui représentent la position du bloc sur la grille de jeu et
sa charge. La charge du bloc est nulle s'il n'est pas polarisé.
La classe sera étendue pour représenter des types de
blocs spécialisés.
Enfin, une classe principale \texttt{Engine} est chargée de
coordonner les éléments du jeu
et d'organiser le dessin des \emph{frames}. Elle est
dotée d'un tableau à deux dimensions d'instances de
\texttt{Block} qui représente la grille de jeu,
d'un tableau à une dimension d'instances de \texttt{Ball}
qui stocke toutes les balles dans le niveau, et d'une
horloge qui mesure le temps écoulé entre chaque \emph{frame}.
La figure \ref{fig:ptf-uml-diagram} présente les classes
utilisées pour la modélisation. Les méthodes de ces classes
sont détaillées dans la section suivante.
\begin{figure}[h!]
\centering
\input{./figures/ptf-uml-diagram}
\caption{Diagramme des classes utilisées}
\label{fig:ptf-uml-diagram}
\end{figure}
\section{Algorithmes}
\label{section:ptf-algos}
\subsection{Physique}
Les balles sont équipées de propriétés représentant leur
position, leur vitesse, leur masse et leur charge comme
vu dans la section précédente. On utilise
l'intégration explicite d'Euler pour calculer la nouvelle
position de chaque balle à chaque \emph{frame}. \cite{ptf-euler}
Cette méthode a l'avantage d'être simple à implémenter et rapide.
\begin{description}
\item[\texttt{Engine::update(delta)}]
L'algorithme reçoit le temps écoulé depuis la dernière \emph{frame}. Il
calcule les forces à appliquer à chaque balle, puis appelle la procédure
\texttt{Ball::update(forces, delta)} en conséquence.
\begin{enumerate}
\item Pour chaque \texttt{ball} dans \texttt{balls}.
\item Initialiser un vecteur \texttt{forces} au vecteur nul.
\item Ajouter le vecteur $(0, g)$, $(0, -g)$, $(g, 0)$, $(-g, 0)$
selon la direction de la gravité au vecteur \texttt{forces}.
\item Si la touche pour faire aller la balle \texttt{ball}
à gauche est enfoncée, ajouter le vecteur $(-m, 0)$ au
vecteur \texttt{forces}.
\item Si la touche pour faire aller la balle \texttt{ball}
à droite est enfoncée, ajouter le vecteur $(m, 0)$ au
vecteur \texttt{forces}.
\item Pour chaque autre élément polarisé, appliquer une
force d'attraction portée par la droite passant par les
deux éléments et de norme $c \times \frac{\mathtt{charge}_1 \times \mathtt{charge}_2}{\mathtt{distance}^2}$.
\item Gérer les collisions et les frottements.
\item Appeler \texttt{Ball::update(forces, delta)} sur \texttt{ball}.
\end{enumerate}
\item[\texttt{Ball::update(forces, delta)}]
L'algorithme reçoit le vecteur somme de toutes les forces appliquées
à la balle et un flottant qui contient le temps écoulé depuis la
dernière \emph{frame}. Il calcule la position suivante de la balle.
\begin{enumerate}
\item $\mathtt{acceleration} := \frac{\mathtt{forces}}{\mathtt{mass}}$.
\item Ajouter $\mathtt{acceleration} \times \mathtt{delta}$ à \texttt{velocity}.
\item Ajouter $\mathtt{velocity} \times \mathtt{delta}$ à \texttt{position}.
\end{enumerate}
\end{description}
Les constantes $g$, $m$ et $c$ devront être définies et
ajustées au cours de la conception du jeu pour que
la simulation paraisse naturelle.
\subsection{Dessin}
La scène du jeu est composée de trois couches, l'une pour
l'arrière-plan du jeu, une autre pour la grille de blocs,
et la dernière pour les balles. Ces couches sont représentées
sur les figures \ref{fig:ptf-layering-exploded} et \ref{fig:ptf-layering-merged}.
Chaque objet susceptible d'être dessiné à l'écran possède
une méthode \texttt{draw()}.
\begin{description}
\item[\texttt{Ball::draw()}] Dessine la balle à sa position sur l'écran.
\item[\texttt{Block::draw()}] Dessine le bloc à sa position sur l'écran.
\item[\texttt{Engine::draw()}] Cet algorithme du moteur appelle les
différentes fonctions de dessin dans un ordre spécifique pour que
les trois couches de la scène du jeu soient correctement affichées.
\begin{enumerate}
\item Dessiner l'arrière-plan du jeu.
\item Dessiner la grille de blocs en appelant \texttt{Block::draw()}
sur les blocs de \texttt{blocks} qui sont visibles à l'écran.
\item Dessiner le premier-plan en appelant \texttt{Ball::draw()} sur
les balles de \texttt{balls} qui sont visibles à l'écran.
\end{enumerate}
\end{description}
\begin{figure}[p!]
\centering
\input{./figures/ptf-layering-exploded}
\caption{Vue explosée des trois couches de rendu du jeu}
\label{fig:ptf-layering-exploded}
\end{figure}
\begin{figure}[p!]
\centering
\input{./figures/ptf-layering-merged}
\caption{Une configuration similaire à celle de la figure \ref{fig:ptf-layering-exploded}, vue de face}
\label{fig:ptf-layering-merged}
\end{figure}
\subsection{Moteur}
\begin{description}
\item[Initialisation du moteur \texttt{Engine}]\hfill
\begin{enumerate}
\item Créer et configurer la fenêtre d'affichage du jeu.
\item Initialiser \texttt{clock} à zéro.
\item Tant que la fenêtre est ouverte~:
\begin{enumerate}
\item traiter tous les événements relatifs à la fenêtre
(notamment l'appui sur une touche, la fermeture, le redimensionnement)~;
\item calculer le temps écoulé \texttt{delta} depuis la
dernière \emph{frame} et réinitialiser \texttt{clock} à zéro~;
\item appeler l'algorithme \texttt{Engine::update(delta)}~;
\item appeler l'algorithme \texttt{Engine::draw()}.
\end{enumerate}
\end{enumerate}
\end{description}
\section{Spécifications}
\subsection{Version initiale}
On choisira le langage C++, qui prend en charge le paradigme objet
et dont la syntaxe est enseignée dans le cursus. On utilisera
la librairie SFML pour son A.P.I. simple et puissante.
Les deux joueurs partageront le clavier d'une même machine.
On utilisera le type \texttt{sf::Vector2d} pour ce qui est
vectoriel (position, vitesse, accélération, forces). Les tableaux
utiliseront le type standard \texttt{std::vector}. Le type
\texttt{sf::Clock} sera utilisé pour l'horloge du moteur. On choisira
entre des flottants simple précision ou double précision en
fonction des besoins.
Des recherches supplémentaires sont nécessaires notamment
concernant les algorithmes de détection et de réaction
aux collisions. \cite{ptf-collision-detection, ptf-collision-response}
\subsection{Améliorations possibles}
L'algorithme physique utilise la méthode explicite d'Euler.
Cette méthode engendre une erreur de simulation d'autant
plus grande que l'espacement entre les \emph{frames} est
élevé, ce qui signifie que la physique du jeu se comportera
différemment selon les performances de la machine. On pourra
opter pour des méthodes plus précises comme l'intégration
de Verlet \cite{ptf-verlet} ou la méthode de Runge-Kutta classique.
\cite{ptf-rk4}
On pourra faire en sorte que le jeu s'exécute en réseau
entre deux machines, une pour chaque joueur. Cela requièrera
une synchronisation de la simulation physique et la mise au point d'un
protocole de communication entre les deux machines.
\section{Organisation}
Dans un premier temps le moteur physique et graphique devra
être conçu sur la base des algorithmes fournis dans le rapport
(hormis l'algorithme de collision, qui devra faire l'objet
de plus de recherches). Durant la mise au point de ce moteur,
un niveau de test sera créé permettant l'appréciation
et l'ajustement des variables physiques. On y consacrera 40 heures
au total.
Ce niveau de test permettra également l'essai de différents
mécanismes de \emph{gameplay.} Ces éléments seront en parallèle
intégrés dans les niveaux finaux. La conception et le
test des niveaux se fera sur 80 heures.
Dans le même temps, l'univers graphique, notamment les textures,
la décoration de l'interface, ainsi que la musique et les bruitages
du jeu seront réalisés. Après la réalisation des éléments
graphiques, on pourra concevoir l'interface du jeu.
On y consacrera 50 heures.
Enfin, les tests finaux du jeu s'effecturont sur 5 heures.
On pourra éventuellement demander l'aide de personnes extérieures
pour ces essais.
La rédaction du rapport s'effectuera en continu pendant la création du jeu.
La figure~\ref{fig:ptf-gantt} présente un diagramme de Gantt résumant
la répartition du travail.
\begin{figure}[h!]
\centering
\input{./figures/ptf-gantt}
\caption{Développement du jeu sur 40 heures}
\label{fig:ptf-gantt}
\end{figure}