Skip to content

A game made during courses at the IT department of the university of Nantes. Based on Lunar Lander from 1979. Artificial intelligence solving the game, and random terrain generation.

License

Notifications You must be signed in to change notification settings

PeiP-2018-Work-Nantes-DUT-INFO/Planet-Lander-Lunar-Lander-with-Pygame

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

94 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Planet Lander (Lunar Lander) with Pygame !

Lunar module

Based on Lunar Lander from 1979 by Atari.

By Adame NAJI & Simon SASSI

Features:

  • Random terrain generation

  • AI playing the game.

  • Fullscreen mode

  • Beautiful demo mode

Official repo:

https://gitlab.univ-nantes.fr/E183694S/planet-lander-python

Game instructions :

Launching the game:

Requirements: pygame >= 1.8.1 python3

Install:

git clone https://github.com/maxerbox/Planet-Lander-with-pygame --branch 1.2-final

cd planet-Lander-with-pygame

pip3 install pygame

To launch the game, run python3 run_game.py

Starting the game in fullscreen mode / changing window size manually.

Go to game_config.py and set ENABLE_FULLSCREEN to True

You can also edit WINDOW_W_WINDOWED/WINDOW_H_WINDOWED variables to change the window size in windowed mode.

Game controls:

Key Description
Arrow left (in game) Rotate aircraft by +2° (to the right)
Arrow right (in game) Rotate aircraft by -2° (to the left)
Arrow Up/ Space Bar (in game) Aircraft boost
Key D (before game) Enable map debug
Key P (before game) Enable trajectory prediction
Key I (before game) Start game with AI
Key U/J (before game) Increase/Decrease number of plateforms
Arrow Up/Down (before game) Increase/Decrease fuel quantity
Key A (before game) Enable demo mode
Key ENTER Launch a new game
Key Q Quit the game

ToDo

  • Implement drag like the original game

  • Random velocity of aircraft when it spawn (fix to 50 vx)

  • Enable map wrapping (player is telepported at the opposite edge when he reach a edge)

  • AI: Estimate the best plateform to land to maximize point (predict fuel use)

  • AI: Calculate the best min height to allow the aircraft to rotate before he stabilize on the plateform

Screenshots / Video

Video

Credits

Credits

Credits

Credits

Code structure is inspired from the game Cabbages and king of Mekire. We are using the same state machine.


Copyright 2018, Sean J. McKiernan

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Report:

Only in french. Report given to the teacher.

Introduction

Dans le cadre du module de modĂ©lisation mathĂ©matique, nous avons dĂ©veloppĂ© un jeu vidĂ©o et une intelligence artificielle capable de jouer Ă  ce jeu. Nous avons choisi de reprendre le jeu “hit” des annĂ©es 80 “Lunar Lander” sur borne arcade. Ce jeu est une “simulation” d'atterrissage sur la lune avec un seul but: poser un module lunaire.

Comment joue t’on ?

Afin de gagner, il pose le module lunaire sur une des plusieurs plateformes dissĂ©minĂ©es dans la zone de jeu. Pour lancer une partie, il suffit d'appuyer sur la touche “entrĂ©e” du jeu, ou sinon laisser jouer l’intelligence artificielle avec la touche I. Les seules actions possibles en jeu par le joueur sont d’agir sur l'orientation du vaisseau ou d’activer le booster principal.

RĂšgles du jeu

  • Il y a une quantitĂ© d’essence limitĂ©e: Ă  chaque fois que le joueur appuie sur la touche ‘Booster’, une quantitĂ© d’essence est consommĂ©e.

  • Il n’y a pas de possibilitĂ© de gagner de l’essence : le nombre d’unitĂ©s d’essence est fixĂ©e au dĂ©but de la partie, et il n’est pas possible d’en obtenir plus ! S’il n’y a plus d’essence, les moteurs s’éteignent et le module lunaire ne peut plus utiliser son booster. Ce comportement est basĂ© sur le jeu originel, ou seul le niveau d’essence pouvait augmenter en mettant des piĂšces dans la borne d'arcade.

  • Il ne faut pas arriver trop vite sur les plateformes: une vitesse horizontale supĂ©rieure Ă  15 ou une vitesse verticale supĂ©rieure Ă  20 fera exploser le module !

  • Il ne faut pas arriver n’importe comment sur les plateformes: un module lunaire doit atterrir perpendiculairement Ă  la plateforme, un angle +- 10° est tolĂ©rĂ©.

  • Si le joueur ne respecte pas une des deux rĂšgles dĂ©crites ci-dessus, son vaisseau explose Ă  l'atterrissage et il perd alors 200 unitĂ©s d’essences. La partie est perdue si l’essence atteint le niveau 0.

  • Le niveau est rĂ©gĂ©nĂ©rĂ© alĂ©atoirement si le joueur arrive Ă  bien se poser.

  • Le module lunaire a une vitesse horizontale initiale de 50 et apparaĂźt dans le coin supĂ©rieur gauche de l’écran en dĂ©but de partie.

  • Il n’y a pas de frottements (il y en a dans le jeu originel) et toucher le bord gauche ou droit de l’écran fait exploser le module.

Score

Chaque fois que le joueur se pose, son score augmente. Une plateforme peut multiplier le score obtenu. La détermination de ce multiplicateur est expliquée plus bas.

Le score est calculé de cette façon:

La rĂ©alisation du projet est dĂ©coupĂ©e en trois Ă©tapes. PremiĂšrement la crĂ©ation du sol lunaire avec des plateformes d'atterrissage et une gĂ©ographie alĂ©atoire. En parallĂšle, le dĂ©veloppement du comportement du module lunaire et de ses trajectoires. Enfin le dĂ©veloppement de l’IA capable de jouer au jeu.

Le sol de la Lune

Le sol de la Lune est gĂ©nĂ©rĂ© alĂ©atoirement Ă  chaque dĂ©but de partie ou bon atterrissage. Il est composĂ© d’un ensemble de plateformes et de points (qui forment le dĂ©cor).

Une plateforme a une taille variable et une position variable. Le nombre de plateforme est dĂ©terminĂ© manuellement avant le dĂ©but de la partie. Les plateformes sont rĂ©parties dans des “zones”: pour N plateformes, l’écran est divisĂ© en N partit. Une plateforme est ensuite positionnĂ©e alĂ©atoirement dans sa partie d’écran, tout en respectant une contrainte de hauteur maximale.

La taille d’une plateforme est mesurĂ©e en segment de 16 px. Une plateforme fait une taille alĂ©atoire qui peut varier de 2 Ă  6 segments. Son multiplicateur de point est dĂ©terminĂ© Ă  partir de sa taille (un tableau liste les diffĂ©rents multiplicateurs possibles, le premier Ă©lĂ©ment du tableau est le plus haut multiplicateur, le dernier le plus bas, c’est-Ă -dire “x1”, on accĂšde au tableau Ă  partir du pourcentage de la taille maximale que la plateforme reprĂ©sente).

Le dĂ©cor est ensuite gĂ©nĂ©rĂ© entre les plateformes. L’algorithme utilisĂ© est “l’algorithme itĂ©ratif de dĂ©placement de point central”.

Cela va permettre, Ă  partir de deux points qui forment un segment (le point de dĂ©but et le point de fin, start, end), d’une duretĂ© (roughness), d’une limite de dĂ©placement (limite), d’un dĂ©placement vertical (vertical_displacement) et d’un nombre d’itĂ©rations (number_of_iterations), de gĂ©nĂ©rer un ensemble de points.

Il fonctionne de la maniĂšre suivante:

  • On prend le milieu d’un segment. On dĂ©coupe ce segment en deux sous-segments (cela crĂ©e un nouveau point ayant pour coordonnĂ©es du milieu du segment).

  • On dĂ©cale ensuite ce point d’un dĂ©placement vertical alĂ©atoire (compris entre -vertical_displacement et +vertical_displacement. Ce dĂ©placement vertical est limitĂ© par limit, un tuple contenant la hauteur minimale et maximale que peut prendre le point. Ce paramĂštre limit est utilisĂ© pour Ă©viter que le dĂ©cor dĂ©borde en dehors de l’écran.

  • On multiplie ensuite le dĂ©placement vertical par:

    Cela permet de “lisser” la courbe que vont former les segments (seulement si la duretĂ© est supĂ©rieure Ă  1).

  • On rĂ©pĂšte l’opĂ©ration N fois (number_of_iterations)

Cela va donc créer (2^{nombre\ d'itérations})segments.

Le nombre d’itĂ©rations Ă  effectuer pour obtenir les points entre deux plateformes est dĂ©terminĂ© Ă  partir du calcul suivant:

Cela permet de garder une longueur de segment en x homogĂšne entre les plateformes. Le dĂ©placement vertical passĂ© Ă  l’algorithme est dĂ©terminĂ© selon cette formule:

Si l’espacement en X entre les deux plateformes est infĂ©rieur Ă  100, alors le dĂ©placement vertical est Ă©gal Ă  la distance du milieu des deux plateformes et des plateformes (cela permet d’éviter d’avoir des pics entre les plateformes proches les unes des autres)

Sinon, le déplacement vertical est égal au minimum entre:

  • la distance entre la plateforme de droite et les bords horizontaux de l’écran

  • l’ordonnĂ©e du point qui est le milieu des deux plateformes

Le module lunaire

Le module lunaire, dĂ©finie par la classe Lander, est caractĂ©risĂ© par sa position sur l’axe des abscisses((x) et des ordonnĂ©es (y) , il nous faut Ă©galement sa vitesse horizontale (vx) et la vitesse verticale (vy), pour finir on enregistre sa masse (m) et son orientation.

Moteur physique

Pour faire avancer le vaisseau, on crĂ©e un vecteur de force basĂ© sur l’angle du vaisseau (orientation) et une accĂ©lĂ©ration (engine_power) dĂ©finie (de maniĂšre Ă  rendre le jeu rĂ©aliste).

$\widehat{F} = \ m*\widehat{a}\ $

Le vecteur de force appliquĂ© sur le vaisseau est orientĂ© Ă  partir de l’orientation de la façon suivante:

${\widehat{F}}_{\text{xengine\ }} = \ \text{mass}e_{\text{module}}\ *\ \text{engin}e_{\text{power}}\ *cos(orientation{}_{\text{module}}*\frac{\Pi}{180})\ $

${\widehat{F}}_{\text{yengine}} = \ \text{mass}e_{\text{module}}\ *\ \text{engin}e_{\text{power}}\ *sin(orientation{}_{\text{module}}*\frac{\Pi}{180})$

Ce vecteur de force n’est appliquĂ© sur le module que lorsque le joueur active les boosters. Il est donc Ă©gal Ă  0 lorsque le joueur n’appuie pas sur la touche.

Le vecteur de gravitĂ© est lui appliquer constamment, c’est une accĂ©lĂ©ration verticale:

$F_{\text{ygrav}_{}} =\)\({\widehat{a}}_{gravité}*masse_{\text{module}}\ $

L’accĂ©lĂ©ration du module en x et en y est obtenue Ă  partir de la somme de toutes les forces que subit le module:

${\widehat{F}}_{x} = {\widehat{F}}_{\text{xengine\ }}\ $

${\widehat{F}}_{y} = {\widehat{F}}_{\text{xengine\ }} + \ F_{\text{ygrav}_{}}\ $

On stocke les coordonnées x et y de ce vecteur (fx et fy). On utilise ces coordonnées pour définir une accélération qui sera décrite horizontalement (ax) et verticalement (ay).

On la calcule ainsi :

Comme (\widehat{F} = \ m*\widehat{a}\ )alors (\widehat{a} = \frac{\widehat{F}}{m}\ ) (\ `$

$\widehat{a_{x}} = \frac{\widehat{F_{x}}}{m}\)\(\widehat{a_{y}} = \frac{\widehat{F_{y}}}{m}$

Une fois l’accĂ©lĂ©ration obtenue, on ajoute cette derniĂšre Ă  la vitesse courante via les formules suivantes : (v_{x} = v_{\text{x\ }} + \widehat{a_{x}}*dt) et (v_{y} = v_{\text{y\ }} + \widehat{a_{y}}*dt`$

$`\text{dt}) correspond au temps écoulé (ce temps est fixé dans le jeu).

La derniÚre étape consiste à mettre à jour les coordonnées du vaisseau y ajoutant la vitesse par rapport à un temps (\text{dt}) prédéfini : (x = x + v_{x}*dt) et (y = y + v_{y}*dt`$

Rotation du module et du triangle

La rotation du module utilise la fonction pygame.transform.rotate qui effectue la rotation d’une surface (image) à partir d’un point.

Cette fonction s'appuie sur une matrice de rotation:

ou (\theta)est l’angle en radian.

Ramené à la distance entre un centre et un point:

Chacun des points de l’image vont ĂȘtre tournĂ©es tour Ă  tour.

Flamme du booster du module lunaire

La “flamme” du module lunaire est un triangle dont la taille grandit quand le joueur appuie sur la touche pour booster et diminue lorsque le joueur n'appuie plus. La flamme fluctue au fur et Ă  mesure du temps. Les points du triangle, qui sont relatifs au centre du vaisseau, utilisent aussi une matrice de rotation. Afin que la transition de disparition de la flamme soit plus rĂ©elle, la hauteur du triangle diminue en fonction de la racine carrĂ©e du temps:

$\text{hauteur}{}_{\text{triangle}} = \ hauteur{}_{\text{triangle}} -$

Prédiction de la trajectoire du module lunaire

La module lunaire prĂ©dit Ă  chaque fois la trajectoire qu’il va effectuer (Ă  des fins visuelles et utilisĂ© par l’intelligence artificielle).

Cette trajectoire est composĂ©e d’un ensemble de points par lesquels le centre du module va passer. Elle est dĂ©terminĂ©e Ă  partir de la vĂ©locitĂ© initiale et de la gravitĂ©. La trajectoire est recalculĂ© lorsque le joueur modifie les forces du module (lorsqu’il utilise le booster). Les points de trajectoire sont obtenues en augmentant le temps passĂ© (\text{dt}) Ă  chaque fois:

$x\ = \ v_{\text{x\ module}}*dt + x_{\text{module}}$

$y = \frac{1}{2}*gravitĂ©\ *\ (dtÂČ)\ + \ v_{\text{y\ module}_{}}*dt\ + y_{\text{module}}$

La formule (\frac{1}{2}*gravitĂ©\ *\ (dtÂČ)) est une simple intĂ©gration de l’accĂ©lĂ©ration.

Par la mĂȘme occasion, un masque qui suit les segments formĂ©s par ces points est crĂ©Ă© (cela est utilisĂ© par l’intelligence artificielle afin de dĂ©terminer s’il va y avoir une collision avec une montagne du terrain avant l’atteinte d’une plateforme, voir le texte ci-dessous sur la dĂ©tection des collisions).

DĂ©tection des collisions

Toutes les collisions sont rĂ©alisĂ©es Ă  partir des “masques” intĂ©grĂ©s Ă  pygame. Ces masques, qui font la taille d’une surface (une surface est une image sur laquelle on va dessiner, par exemple l’écran en est une), sont composĂ©s d’une matrice de boolĂ©en. Cette matrice de boolĂ©en est dĂ©terminĂ© Ă  partir des pixels de la surface qui sont opaques (si leur opacitĂ© est au-dessus d’un certain seuil). Ces masques permettent de dĂ©tecter des collisions aux pixels prĂȘts. Un masque est appliquĂ© sur le module lunaire, le sol de la lune et les plateformes. Les masques sont comparĂ©s Ă  chaque mise Ă  jour du jeu (Ă  chaque tour de boucle) bit Ă  bit de façon diagonale[1] afin de dĂ©terminer s’il y a collision ou non.

L’intelligence artificielle

L’intelligence artificiel n’envoie que des entrĂ©es claviers. Elle n’agit pas sur les Ă©lĂ©ments du jeu. Elle a accĂšs Ă  la configuration du sol de la lune, l’état du module, notamment sa vitesse, sa trajectoire, son orientation etc.

Artificial Intelligence 1 (atterrissage vertical)

La premiĂšre IA fonctionne en apprenant de ses erreurs. Elle dĂ©coupe la fenĂȘtre de jeu en 3 parties. Lorsque le rover est dans la partie rouge Ă  gauche, il est maintenu Ă  une hauteur minimale de 550. Dans le cas oĂč le vaisseau tombe en dessous de cette altitude, il doit s’orienter vers le haut et effectuer une poussĂ© jusqu'Ă  avoir une altitude supĂ©rieure Ă  550 et une vitesse vy de -10 (donc +10 vers le haut). Lorsque le rover est dans la partie rouge Ă  droite, il devient impossible pour lui d’atteindre la plateforme et va donc se laisser tomber sur la surface de la Lune. Enfin lorsque le vaisseau se trouve dans la zone jaune, il est en phase de dĂ©cĂ©lĂ©ration. Cette zone est dĂ©limitĂ©e par une variable distance et c’est cette variable que l’IA modifie pour finir une partie.

Lorsque que le vaisseau est en phase de dĂ©cĂ©lĂ©ration, l’IA oriente le moteur dans la direction opposĂ© Ă  la vitesse horizontale et accĂ©lĂšre jusqu’à avoir une vitesse vx de 0. Le vaisseau va alors se laisser tomber vers le bas en maintenant une vitesse infĂ©rieure Ă  la vitesse maximale autorisĂ©e pour atterrir. L’IA ne sait pas si le vaisseau est bien au-dessus de la plateforme, mais elle va quand mĂȘme tenter de poser le vaisseau.

L’IA va ensuite entrer dans une phase de recherche de la distance idĂ©ale pour dĂ©cĂ©lĂ©rer via un algorithme de recherche dichotomique. Si le vaisseau atterrit Ă  droite de la plateforme, cela signifie que la distance Ă©tait insuffisante pour dĂ©cĂ©lĂ©rer donc on la multiplie par 1.5. Dans le cas oĂč le vaisseau est Ă  gauche, cela signifie que la distance Ă©tait trop grande et on la divise par deux. Au fur et Ă  mesure des Ă©checs on augmente la prĂ©cision de l’IA.

Artificial Intelligence 2 (atterrissage vertical parfait)

La seconde IA est plus complĂšte que la premiĂšre avec un fonctionnement mathĂ©matique totalement diffĂ©rent, en plus des exigences de la premiĂšre IA, on rajoute le fait d’économiser le carburant. On effectue les poussĂ©es strictement nĂ©cessaire pour mettre le module lunaire au-dessus de la plateforme ayant le plus haut multiplicateur de score. L’IA va donc faire en sorte d’avoir une vĂ©locitĂ© horizontale de 0 au-dessus de la plateforme, et dĂ©terminer la distance minimale Ă  partir de laquelle il faut activer la pousse inverse. Elle va ensuite se laisser tomber, puis effectuer la mĂȘme chose verticalement: elle va dĂ©terminer Ă  partir de quand il va falloir activer le booster pour rĂ©aliser un atterrissage parfait. Elle va aussi effectuer une poussĂ©e verticale pour Ă©viter les montagnes qui se situeraient devant la plateforme visĂ©e.

La distance minimale Ă  partir de laquelle activer la “poussĂ©e inverse” (le module est orientĂ© Ă  -180° afin d’annuler sa vĂ©locitĂ© horizontale) est dĂ©terminĂ© Ă  partir de la formule suivante:

$\text{distanc}e_{\text{minimal}} = \frac{v_{x}ÂČ}{2*a}$

ou (v_{x})est la vitesse horizontale du module et (a)est l’accĂ©lĂ©ration du module (Ă©gale Ă  engine_power)

Lorsque le module se trouve au-dessus de la plateforme, il s’oriente Ă  90° afin d’ĂȘtre dans son axe. La distance minimum Ă  partir de laquelle activer le booster est calculĂ©e en “prĂ©disant le futur”:

En augmentant (\text{dt})avec un petit pas Ă  chaque fois, on obtient la vitesse verticale et la distance verticale parcourue Ă  chaque instant.

$v_{y} = v_{\text{y\ module}} + \ g\ *dt$

$d_{y} = 0.5\ *\ g\ *\ iÂČ\ + \ v_{\text{y\ module}}\ *\ dt$

A chaque futur instant, on peut ainsi calculer la distance minimale nĂ©cessaire Ă  partir de la vitesse Ă  l’instant:

$\text{distanc}e_{\text{minimal}} = \frac{v_{y}ÂČ}{2*a}\)ou \(a = engine_{\text{power}} - g$

Si cette distance minimale est trop grande (qu’elle dĂ©passe la plateforme, c’est Ă  cet instant que l’on doit activer le booster).

L’IA Ă©vite les montagnes en effectuant une poussĂ©e au dĂ©but de la partie, tant que la trajectoire du module est en collision avec la montagne (en utilisant le masque de la trajectoire).

  1. Source: bitmap.c du dépÎt officiel de pygame

About

A game made during courses at the IT department of the university of Nantes. Based on Lunar Lander from 1979. Artificial intelligence solving the game, and random terrain generation.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages