Forum d'entraide à la création de jeux d'aventure
 
PortailPortail  AccueilAccueil  RechercherRechercher  S'enregistrerS'enregistrer  Connexion  

 

 [Tuto] Tetris

Aller en bas 
+2
Shai-la
Asraroth
6 participants
AuteurMessage
Asraroth
Disciple de la Grande Tasse Bleue
Disciple de la Grande Tasse Bleue
Asraroth


Nombre de messages : 1450

Age : 49

Date d'inscription : 20/10/2006


[Tuto] Tetris Empty
MessageSujet: [Tuto] Tetris   [Tuto] Tetris EmptyVen 22 Mai 2009 - 20:33

Voici un tutoriel pour réaliser un TETRIS tout simple sous AGS.
Le résultat final va donner çà : [Tuto] Tetris Tetris

Le jeu complet est téléchargeable ici : tetris.zip

Et le template : TemplateTetris.zip

Je n'ai pas tout détaillé ligne par ligne. N'hesitez pas à demander plus d'explications si besoin sourire


Dernière édition par Asraroth le Lun 25 Mai 2009 - 8:56, édité 1 fois
Revenir en haut Aller en bas
Asraroth
Disciple de la Grande Tasse Bleue
Disciple de la Grande Tasse Bleue
Asraroth


Nombre de messages : 1450

Age : 49

Date d'inscription : 20/10/2006


[Tuto] Tetris Empty
MessageSujet: I - Le moteur   [Tuto] Tetris EmptyVen 22 Mai 2009 - 20:33

I - Le Moteur

a) La matrice

AGS ne gère pas les tableaux à plusieurs dimensions. Voici, donc, un petit module matint110 qui permet de gérer une matrice de taille variable d'entiers (Int).
Ce module comprend 3 fonctions :
- matint_init(longueur, hauteur) = création de la matrice
- matint_set(int x, int y, int valeur) = positionne une valeur dans la case X,Y de la matrice
- matint_get(int x, int y) = renvoie la valeur de la case X,Y
Pour initialiser notre matrice de jeu, on fera un : matint_init(10, 20); // 10 cases de large, par 20 cases de haut

b) La pièce

La pièce qui chute a plusieurs propriétés tel que :
- sa forme
- sa couleur
- sa position

Voici la structure que j'ai adopté pour gérer tout çà :
Code:
struct Piece {
  int type;          // Type de piece
  int pos_x;          // Coordonnées de la piece dans la matrice
  int pos_y;
  int couleur;        // Couleur de la piece
  int structure[16];  // Structure de la piece (4 * 4)
  int structavp[16];  // Sauvegarde de la structure avant de pivoter la piece (permet d'annuler la rotation)

  import function creer_structure();            // Créer la structure en fonction du type
  import function pivoter();                    // Pivote la structure
  import function annuler_pivoter();            // Annule le pivot
  import function get_structure(int x, int y);  // renvoie la valeur d'une case de la structure en X,Y
};

La pièce est représentée par une petite matrice de 4 * 4 (int structure[16]).
La fonction "creer_structure()" permet de remplir cette structure à partir du type de pièce (7 types de pièce différents).
Elle calcule la position de départ "px" dans le dessin que forme les 4 lignes, et recopie un carré de 4 * 4 dans la structure en fonction des "X" et des "."
Les "X" sont remplacés par le numéro de la couleur de la pièce alors que les "." sont remplacés par des 0.

Code:
function Piece::creer_structure() {

  String ligne[4];  // Dessin des 7 types de pièces
  ligne[0] = ".... .X.. .... .XX. .XX. .... ....";
  ligne[1] = ".XX. .X.. .X.. .X.. ..X. .XX. .XX.";
  ligne[2] = ".XX. .X.. XXX. .X.. ..X. XX.. ..XX";
  ligne[3] = ".... .X.. .... .... .... .... ....";

  if ((this.type > 0) && (this.type <= 7)) {

    // Choix de la couleur de la pièce en fonction de sa forme.
    if (this.type == 1) this.couleur = 9;
    if (this.type == 2) this.couleur = 40;
    if (this.type == 3) this.couleur = 14;
    if (this.type == 4) this.couleur = 37;
    if (this.type == 5) this.couleur = 10;
    if (this.type == 6) this.couleur = 11;
    if (this.type == 7) this.couleur = 36;

    int px = (this.type - 1) * 5;  // Remplissage de la structure à partir du dessin des 4 lignes
    int l = 0;
    int i = 0;
    while (l < 4) {
      int c = 0;
      while (c < 4) {
        if (ligne[l].Chars[px + c] == 'X') {  // un "X" = la couleur de la piece, sinon = 0
          this.structure[i] = this.couleur;
        } else {
          this.structure[i] = 0;
        }
        i++;
        c++;
      }
      l++;
    }
  } else {        // Si type inconnu, on vide la structure
    int i = 0;
    while (i < 16) {
      this.structure[i] = 0;
      i++;
    }
  }
}


c) La rotation

Alors là, ma façon de faire est un peu tordue, mais çà marche. Il y a surement plus simple pour parvenir au même résultat.
Dans un premier temps, on sauvegarde la mini-matrice de la structure (4 * 4) pour pouvoir annuler rapidement la rotation.
Ensuite, on recopie la mini-matrice dans une autre mini-matrice temporaire en appliquant la rotation.
Puis, on recopie le résultat de cette matrice temporaire dans la structure.
Code:
function Piece::pivoter() {
  // Sauvegarde la structure dans "structavp"
  int i = 0;
  while (i < 16) {
    this.structavp[i] = this.structure[i];
    i++;
  }
  // Pivote la structure dans "structbis"
  int structbis[16];
  int xs = 0;
  int ys = 0;
  int xd = 3;
  int yd = 0;
  while (ys < 4) {
    xs = 0;
    yd = 0;
    while (xs < 4) {
      structbis[yd * 4 + xd] = this.structure[ys * 4 + xs]; 
      yd++;
      xs++;
    }
    ys++;
    xd--;
  }
  // Recopie "structbis" dans la structure
  i = 0;
  while (i < 16) {
    this.structure[i] = structbis[i];
    i++;
  }
}

La fonction qui annule la rotation est toute bête. On recopie la sauvegarde de la structure dans la structure elle-même.
Çà va servir si la rotation n'est finalement pas possible (trop prêt d'un bord, par exemple).
Code:
function Piece::annuler_pivoter() {
  // Recopie "structavp" dans la structure
  int i = 0;
  while (i < 16) {
    this.structure[i] = this.structavp[i];
    i++;
  }
}

d) La chute

Voici le cœur du jeu: la fonction qui fait tomber la pièce.
Elle appelle tout un tas d'autres fonctions.
Code:
function chutte_piece(){            // fait tomber la pièce d'une case
    if (jeu_encours) {                    // boolean qui indique si le jeu a commencé
      supprime_structure_dans_matrice();  // Efface la pièce de la grille
      if (controle_structure_dans_matrice(piece_active.pos_x, piece_active.pos_y + 1) == 0) { // Controle des collisions si la grille descend d'une case
        piece_active.pos_y++;              // Pas de collision, la pièce peut descendre
        copie_structure_dans_matrice();    // Insère la piece dans la grille à sa nouvelle position
      } else {                // Collision = la pièce ne peut plus bouger = nouvelle pièce
        copie_structure_dans_matrice();    // replace la pièce sans la deplacer
        controle_lignes();                // Lance le contrôle des lignes complètes + scoring

        // Recopie de la piece "suivante" dans la piece "active"
        piece_active.type = piece_suivante.type;
        piece_active.pos_x = piece_suivante.pos_x;
        piece_active.pos_y = piece_suivante.pos_y;
        piece_active.couleur = piece_suivante.couleur;
        int i = 0;
        while (i < 16) {
          piece_active.structure[i] = piece_suivante.structure[i];
          piece_active.structavp[i] = piece_suivante.structavp[i];
          i++;
        }

        // Préparation de la pièce suivante
        piece_suivante.type = Random(6) + 1;
        piece_suivante.creer_structure();
        piece_suivante.pos_x = 3;
        if ((piece_suivante.type == 1) || (piece_suivante.type == 3) || (piece_suivante.type == 6) || (piece_suivante.type == 7)) {
          piece_suivante.pos_y = -1;
        } else {
          piece_suivante.pos_y = 0;
        }
       
        // Contrôle que la nouvelle pièce n'est pas en collision avec une autre pièce
        if (controle_structure_dans_matrice(piece_active.pos_x, piece_active.pos_y) != 0) { // PERDU
          jeu_encours = false;
          piece_active.type = 0;
        }
        copie_structure_dans_matrice();    // Insère la pièce dans la grille
      }
      affiche_matrice();                  // Affichage de la matrice
    }
}

Les fonctions suivantes permettent d'insérer et de supprimer la structure (mini matrice 4*4) de la pièce dans la matrice de jeu.
Code:
function copie_structure_dans_matrice(){ // Insertion de la pièce en cours, dans la grille
  int j = 0;
  while (j < 4) {
    int i = 0;
    while (i < 4) {
      int c = piece_active.get_structure(i, j);
      if (c > 0) {
        matint_set(piece_active.pos_x + i, piece_active.pos_y + j, c);
      }
      i++;
    }
    j++;
  }
}

function supprime_structure_dans_matrice(){ // Efface la pièce de la grille
  int j = 0;
  while (j < 4) {
    int i = 0;
    while (i < 4) {
      int c = piece_active.get_structure(i, j);
      if (c > 0) {
        matint_set(piece_active.pos_x + i, piece_active.pos_y + j, 0);
      }
      i++;
    }
    j++;
  }
}

e) Les collisions

Cette fonction qui est appelée à chaque fois que la pièce se déplace (chute, ou déplacement gauche - droite par l'action du joueur) ou qu'elle pivote.
Elle vérifie que la structure de la pièce n'entre pas en collision avec un bord ou le tas d'autres pièce en bas de la matrice.
Code:
function controle_structure_dans_matrice(int x, int y){ // Contrôle des collisions de la pièce
  int j = 0;
  while (j < 4) {
    int i = 0;
    while (i < 4) {
      int c = piece_active.get_structure(i, j);
      if (c > 0) {
        if (matint_get(x + i, y + j) == -1) return -1;  // Collision avec un bord
        if (matint_get(x + i, y + j) > 0) return 1;    // Collision avec une autre pièce
      }
      i++;
    }
    j++;
  }
  return 0;
}


f) Les lignes remplies et la gestion du score

Cette fonction est appelée à chaque fois qu'une pièce arrive en bas de la matrice et s'immobilise. Elle balaye la matrice ligne par ligne et contrôle que la ligne est remplie. Si c'est le cas, la ligne est

effacée, et toutes les lignes du dessus sont décalées vers le bas. En même temps, on compte le nombre de lignes formées (4 maxi avec les pièces standard = Tetris) pour gérer le score.

Code:
function controle_lignes() {  // Contrôle et efface les lignes complètes
 
  int nb_lignes = 0;  // Nombre de lignes complètes (0 à 4 = TETRIS)
  int j = 0;
  while (j < MAX_Y) { // Parcours de la grille de haut en bas
    bool ligne = true;
    int i = 0;
    while ((i < MAX_X) && (ligne)) {            // Controle si la ligne "j" est complète
      if (matint_get(i, j) == 0) ligne = false; // un 0 => pas complète
      i++;
    }
    if (ligne) {              // Si la ligne est complète
      nb_lignes++;
      int v = 0;
      while (v < MAX_X) {    // Efface la ligne (utile que pour la 1ère ligne tout en haut)
        matint_set(v, j, 0);
        v++;
      }
      int dy = j;
      while (dy > 0) {        // Décale toutes les lignes vers le bas
        int dx = 0;
        while (dx < MAX_X) {
          matint_set(dx, dy, matint_get(dx, dy - 1));
          dx++;
        }
        dy--;
      }
    }
    j++;
  }
 
  // Gestion du changement de niveau et du Score
  passniveau = passniveau + nb_lignes;
  if (passniveau > 10) {
    passniveau = 0;
    niveau++;
    LabelNiveau.Text = String.Format("Niveau : %d" ,  niveau);
    if (vitesse > 10) vitesse = vitesse - 5;
  }
  if (nb_lignes == 1) score = score + 10;
  if (nb_lignes == 2) score = score + 30;
  if (nb_lignes == 3) score = score + 60;
  if (nb_lignes == 4) score = score + 100;
  LabelScore.Text = String.Format("Score : %d" ,  score);
}


Dernière édition par Asraroth le Ven 22 Mai 2009 - 21:01, édité 2 fois
Revenir en haut Aller en bas
Asraroth
Disciple de la Grande Tasse Bleue
Disciple de la Grande Tasse Bleue
Asraroth


Nombre de messages : 1450

Age : 49

Date d'inscription : 20/10/2006


[Tuto] Tetris Empty
MessageSujet: II - L''''interface   [Tuto] Tetris EmptyVen 22 Mai 2009 - 20:34

II - L'interface

Cette partie est très courte et assez simple. Je n'entre pas dans le détail du GUI qui affiche le score et qui permet de lancer le jeu ou d'en sortir.

Le contrôle du jeu se fait par la fonction "on_key_press". Dès que le joueur appuie sur une touche, cette fonction est appelée par le moteur d'AGS. Dans notre cas, il suffit de tester si l'une des 4 touches qui nous intéresse a été actionné, et de faire l'action appropriée :

- flèche bas = accélère la chute de la pièce
- flèche gauche = déplace la pièce d'une case vers la gauche
- flèche droite = déplace la pièce d'une case vers la droite
- barre d'espace = fait pivoter la pièce de 90° vers la droite


Code:
function on_key_press(int keycode) {

  if (keycode == 380) { // Fleche bas
    chutte_piece();
  }

  if (keycode == 375) { // Fleche gauche
    supprime_structure_dans_matrice();
    if (controle_structure_dans_matrice(piece_active.pos_x - 1, piece_active.pos_y) == 0) {
      piece_active.pos_x--;
    }
    copie_structure_dans_matrice();
    affiche_matrice();
  }

  if (keycode == 377) { // Fleche droite
    supprime_structure_dans_matrice();
    if (controle_structure_dans_matrice(piece_active.pos_x + 1, piece_active.pos_y) == 0) {
      piece_active.pos_x++;
    }
    copie_structure_dans_matrice();
    affiche_matrice();
  }

  if (keycode == 32) { // Barre d'espace = pivoter
    supprime_structure_dans_matrice();
    piece_active.pivoter();
    if (controle_structure_dans_matrice(piece_active.pos_x, piece_active.pos_y) != 0) {
      piece_active.annuler_pivoter();
    }
    copie_structure_dans_matrice();
    affiche_matrice();
  }

 
}


Dernière édition par Asraroth le Ven 22 Mai 2009 - 21:29, édité 1 fois
Revenir en haut Aller en bas
Asraroth
Disciple de la Grande Tasse Bleue
Disciple de la Grande Tasse Bleue
Asraroth


Nombre de messages : 1450

Age : 49

Date d'inscription : 20/10/2006


[Tuto] Tetris Empty
MessageSujet: III - L''''affichage   [Tuto] Tetris EmptyVen 22 Mai 2009 - 20:34

III - L'affichage

Il n'existe pas de fonction AGS pour dessiner un rectangle vide (une case de la matrice). Il y a une fonction pour dessiner un rectangle plein (DrawRectangle), et une fonction pour dessiner un traie (DrawLine). Voici une petite fonction pour combler ce manque :

Code:
function DrawBox(this DrawingSurface*, int x1, int y1, int x2, int y2){ // Dessine une boite
  this.DrawLine(x1, y1, x1, y2);
  this.DrawLine(x1, y2, x2, y2);
  this.DrawLine(x2, y2, x2, y1);
  this.DrawLine(x2, y1, x1, y1);
}

Pour l'affichage de la matrice, tout se passe dans cette fonction :

Code:
#define MAT_X 220    // Position X de la grille
#define MAT_Y 20      // Position Y de la grille
#define CEL_W 16      // Largeur d'une case
#define CEL_H 16      // Hauteur d'une case
#define GAP_H 1      // Espacement horizontal entre chaque case
#define GAP_V 1      // Espacement vertical entre chaque case
#define MAX_X 10      // Nombre de cases horizontales
#define MAX_Y 20      // Nombre de cases verticales

function affiche_matrice(){ // Affichage de la matrice
  DrawingSurface *surface = Room.GetDrawingSurfaceForBackground();
  surface.UseHighResCoordinates = true;
  // Parcours de la matrice
  int j = 0;
  while (j < MAX_Y){
    int i = 0;
    while (i < MAX_X){
      // Dessin de la petite boite
      surface.DrawingColor = 15;
      surface.DrawBox(MAT_X + (i * CEL_W) + (i * GAP_H), MAT_Y + (j * CEL_H) + (j * GAP_V), MAT_X + ((i + 1) * CEL_W) + ((i + 1) * GAP_H) ,  MAT_Y + ((j + 1) * CEL_H) + ((j + 1) * GAP_V));
      // Coloriage de la boite en fonction du contenu de la matrice
      surface.DrawingColor = matint_get(i, j);
      surface.DrawRectangle(MAT_X + (i * CEL_W) + (i * GAP_H) + GAP_H, MAT_Y + (j * CEL_H) + (j * GAP_V) + GAP_V, MAT_X + ((i + 1) * CEL_W) + ((i + 1) * GAP_H) - GAP_H ,  MAT_Y + ((j + 1) * CEL_H) + ((j + 1) * GAP_V) - GAP_V);
      i++;
    }
    j++;
  }
  surface.DrawingColor = 255;
  surface.DrawBox(MAT_X, MAT_Y, MAT_X + (MAX_X * (CEL_W + GAP_H)),  MAT_Y + (MAX_Y * (CEL_H + GAP_V)));
 
  surface.Release();
}

Au lancement du jeu, on efface l'écran en traçant un rectangle noir de la taille de l'écran.

Code:
function room_AfterFadeIn()
{
  // Efface l'écran
  DrawingSurface *surface = Room.GetDrawingSurfaceForBackground();
  surface.UseHighResCoordinates = true;
  surface.DrawingColor = 0;
  surface.DrawRectangle(0, 0, surface.Width, surface.Height);
  surface.Release();
 
  // Vide et affiche la matrice
  matint_init(MAX_X, MAX_Y, 0);
  affiche_matrice();
}
Revenir en haut Aller en bas
Asraroth
Disciple de la Grande Tasse Bleue
Disciple de la Grande Tasse Bleue
Asraroth


Nombre de messages : 1450

Age : 49

Date d'inscription : 20/10/2006


[Tuto] Tetris Empty
MessageSujet: IV - Le reste   [Tuto] Tetris EmptyVen 22 Mai 2009 - 21:44

[réservé]
Revenir en haut Aller en bas
Asraroth
Disciple de la Grande Tasse Bleue
Disciple de la Grande Tasse Bleue
Asraroth


Nombre de messages : 1450

Age : 49

Date d'inscription : 20/10/2006


[Tuto] Tetris Empty
MessageSujet: Re: [Tuto] Tetris   [Tuto] Tetris EmptyLun 25 Mai 2009 - 8:58

J'ai ajouté le lien pour télécharger le template dans le 1er message.
Revenir en haut Aller en bas
Shai-la
Ouvrière en Chef de la Grande Tasse Bleue
Ouvrière en Chef de la Grande Tasse Bleue
Shai-la


Nombre de messages : 6018

Age : 45

Localisation : Montpellier

Date d'inscription : 17/04/2006


[Tuto] Tetris Empty
MessageSujet: Re: [Tuto] Tetris   [Tuto] Tetris EmptyLun 25 Mai 2009 - 10:24

Super merci !!! sourire [Tuto] Tetris 114419
Revenir en haut Aller en bas
http://marionpoinsot.fr/video
Godzillu
Grand Cliqueur Royal
Grand Cliqueur Royal
Godzillu


Nombre de messages : 1653

Date d'inscription : 11/03/2007


[Tuto] Tetris Empty
MessageSujet: Re: [Tuto] Tetris   [Tuto] Tetris EmptyLun 25 Mai 2009 - 10:27

Excellent!coeur
Revenir en haut Aller en bas
http://mr-godzillu.over-blog.com/
Kromagnon
Disciple de la Grande Tasse Bleue
Disciple de la Grande Tasse Bleue
Kromagnon


Nombre de messages : 1015

Age : 39

Localisation : Finistère

Date d'inscription : 19/09/2006


[Tuto] Tetris Empty
MessageSujet: Re: [Tuto] Tetris   [Tuto] Tetris EmptyLun 25 Mai 2009 - 14:16

Carrement extra B)
Shai-La et toi vous êtes des grands malades pour reussir a programmer des trucs comme ça sur AGS O_O
Revenir en haut Aller en bas
Shai-la
Ouvrière en Chef de la Grande Tasse Bleue
Ouvrière en Chef de la Grande Tasse Bleue
Shai-la


Nombre de messages : 6018

Age : 45

Localisation : Montpellier

Date d'inscription : 17/04/2006


[Tuto] Tetris Empty
MessageSujet: Re: [Tuto] Tetris   [Tuto] Tetris EmptyLun 25 Mai 2009 - 17:37

Je rappelle que c'est lui aussi qui a conçu le moteur de jeu match-3, moi j'ai seulement fait l'enrobage ^^
Revenir en haut Aller en bas
http://marionpoinsot.fr/video
Crazy Legs
Grand Cliqueur Royal
Grand Cliqueur Royal
Crazy Legs


Nombre de messages : 1513

Age : 31

Localisation : La Rochelle

Date d'inscription : 09/01/2008


[Tuto] Tetris Empty
MessageSujet: Re: [Tuto] Tetris   [Tuto] Tetris EmptyLun 25 Mai 2009 - 18:47

Salut tout le monde.
Bravo Asraroth pour ce joli Tetris ; ton code source va approfondir mes connaissances sourire

Spoiler:
Revenir en haut Aller en bas
Asraroth
Disciple de la Grande Tasse Bleue
Disciple de la Grande Tasse Bleue
Asraroth


Nombre de messages : 1450

Age : 49

Date d'inscription : 20/10/2006


[Tuto] Tetris Empty
MessageSujet: Re: [Tuto] Tetris   [Tuto] Tetris EmptyLun 25 Mai 2009 - 19:45

Crazy Legs a écrit:
]De mon côté je programme un jeu de Poker avec AGS.

J'en ai fait un en C++ (sous DOS) il y a + de 15 ans quand j'étais étudiant, et un autre, il y a 3 ans en Visual Basic avant de découvrir AGS.
Et bien, tu as de longues heures de programmation en perspective sourire Bon courage ! Surtout quand tu vas attaquer l"IA" du bluff : Faudra pas trop abuser du Random pour rester cohérent. ^^
Revenir en haut Aller en bas
Crazy Legs
Grand Cliqueur Royal
Grand Cliqueur Royal
Crazy Legs


Nombre de messages : 1513

Age : 31

Localisation : La Rochelle

Date d'inscription : 09/01/2008


[Tuto] Tetris Empty
MessageSujet: Re: [Tuto] Tetris   [Tuto] Tetris EmptyLun 25 Mai 2009 - 19:51

Merci !
Ouais je vais essayer de bien gérer l'IA parce qu'on ne pourra jouer que contre l'ordinateur (du moins je pense m'arrêter là).

Le random n'est appelé que pour le tirage des cartes ; l'IA je pense que je vais faire quelques calculs de probabilité dans un premier temps puis j'ajouterai un coefficient Bluff effectivement (même si les meilleurs joueurs sont les joueurs serrés selon moi ^^ ).
En tout cas coder avec AGS est un grand plaisir [Tuto] Tetris 114419

VIVE AGS !!!
Revenir en haut Aller en bas
jpcr
Cliqueur Amateur
Cliqueur Amateur
jpcr


Nombre de messages : 230

Age : 57

Localisation : Region Parisienne

Date d'inscription : 01/10/2006


[Tuto] Tetris Empty
MessageSujet: Re: [Tuto] Tetris   [Tuto] Tetris EmptySam 21 Aoû 2010 - 9:49

salut Asraroth ,

impossble de telecharger le jeu ou le template .

pourrais tu revoir les liens, stp ?

edit : c'est bon , ,jai reussi... merci

merci
jp
Revenir en haut Aller en bas
https://jpcr.itch.io/
Asraroth
Disciple de la Grande Tasse Bleue
Disciple de la Grande Tasse Bleue
Asraroth


Nombre de messages : 1450

Age : 49

Date d'inscription : 20/10/2006


[Tuto] Tetris Empty
MessageSujet: Re: [Tuto] Tetris   [Tuto] Tetris EmptySam 21 Aoû 2010 - 13:45

Apparemment, il y a eu un changement sur le forum qui fait qu'on ne peut plus mettre d'URL avec des "?"... Ca vient de forumactif ou de Kozzy ?
Revenir en haut Aller en bas
Contenu sponsorisé





[Tuto] Tetris Empty
MessageSujet: Re: [Tuto] Tetris   [Tuto] Tetris Empty

Revenir en haut Aller en bas
 
[Tuto] Tetris
Revenir en haut 
Page 1 sur 1

Permission de ce forum:Vous ne pouvez pas répondre aux sujets dans ce forum
Adventure Games Studio fr :: CREATION DE JEUX :: Trucs & Astuces, Tutoriaux-
Sauter vers: