Canalblog
Suivre ce blog Administration + Créer mon blog

deshayesdivers

12 janvier 2012

GM pour un jeu d'échecs sans ia?

Pour commencer, il faut dessiner l'échiquier. Pour cela un objet controler doit être créé afin de lui assigner les tâches de draw (je crois qu'il lui faut quand même une sprite pour que l'action draw soit prise en compte, mais je n'en suis pas sûr.) Ceci fait, il faut mettre un script dans draw (onglet control).
Nous allons utiliser la boucle for, qui sert à répéter un certain nombre de fois une action.
for(i=0;i<8;i+=1)
    {
    }
i=0 initialise la variable i à 0, i+=1 signifie qu'à chaque fin de boucle i est augmenté d'un. i aura donc les valeurs de 0 à 7, pour dessiner les 8 cases. Il faut cependant définir les conditions selon lesquelles on choisit de dessiner une case noire ou blanche. Avec frac(x), on obtient la partie décimale d'un nombre, donc si cette fonction est égale à 0, c'est que le nombre x, que l'on divisera par 2, est pair. nb je n'ai pas testé.
for(i=0;i<8;i+=1)
    {
    for(j=0;j<8;j+=1)
        {
        if frac(i/2)==0
            {
            if frac(j/2)==0
                {
                draw_set_color(c_white);
                draw_rectangle(i*80+100,j*80+100,i*80+180,j*80+180,false);
                }
           else
                {
               draw_set_color(c_black);
               draw_rectangle(i*80+100,j*80+100,i*80+180,j*80+180,false);
                }
           }
      else
          {
          if frac(j/2)==0
              {
              draw_set_color(c_black);
              draw_rectangle(i*80+100,j*80+100,i*80+180,j*80+180,false);
              }
          else
              {
              draw_set_color(c_white);
              draw_rectangle(i*80+100,j*80+100,i*80+180,j*80+180,false);
              }
         }
     }
}
draw_set_color sert à définir la couleur pour la fonction draw, draw_rectangle dessine la case.
Les deux premiers chiffres sont les coordonnées du rectangle en haut à gauche, les deux autres en bas à droite. On ajoute 100 pour ne pas dessiner l'échiquier tout en haut à gauche, mais ça ne suffira pas pour le centrer. On multiplie les coordonnées par 80 pour faire des cases de 80 pixels, false signifie qu'on ne dessine pas le pourtour.
Voila, en théorie on a un super échiquier en lançant le jeu, mais c'est pas testé.
Bon j'ai mis les espaces à coté des accolades pour des prunes

Ensuite il faut créer des sprites pour toutes les pièces... Ou télécharger des images libres de droit,
créer un objet par type de pièce et par joueur, plus deux objets parents qu'on peut nommer, par exemple, j_piece et o_piece. Il faudra, pour les objets du joueur, spécifier comme parent j_piece, pour celles de l'ordi, qui ne bougeront pas avant longtemps, o_piece. Les objets parents sont en quelque sorte le comportement par défaut pour les objets enfants, mais si ceux-ci ont un event similaire à celui du parent, l'event du parent est ignoré.

On peut ensuite poser les objets dans la room, mais cela est difficile car le quadrillage de l'éditeur ne correspond pas au notre, et assigner dans l'event create de j_piece et o_piece les coordonnées de la case, auquel cas l'objet apparaîtra en haut à gauche de celle-ci, avec:
id.x=floor((id.x-100)/80);
id.y=floor((id.y-100)/80);
Ici, le programme lors de la création de l'instance de l'objet assigne ses coordonnées (x et y), par le biais de "." : id sert à définir l'instance de l'objet, puis ses coordonnées sont modifiées en fonction de l'endroit où il est créé. floor sert à arrondir en dessous.
L'autre solution est de créer les objets un par un dans le creation code de la room:
ex: instance_create(100,100+80*6,j_pion); instance_create(100+80*1,100+80*6,j_pion);
créé des pions en A2, en B2 avec j_pion pour nom de l'objet définissant le pion. On peut utiliser une boucle for pour créer les pions.

Bouger les pions.
On va prendre comme système: un clic sur la pièce signifie qu'elle est sélectionnée, puis un clic sur l'échiquier la déplace.
Il faut d'abord retrouver l'id de l'objet cliqué. Dans l'objet j_piece, on peut mettre un event left pressed, ce qui signifie que l'objet réagit une fois à un clic sur lui-même, avec le code:
oclic=id;
en ajoutant aussi dans l'event create du controler:
globalvar oclic;
oclic=noone;
Nous avons défini une variable globale oclic, qui subsiste tout au long du jeu, contenant par défaut la valeur noone (c'est une valeur spéciale renvoyée par les fonctions comme instance_position signifiant qu'aucun objet n'a été trouvé). Quand l'utilisateur clique sur une pièce, l'opérateur = renvoie l'id dans oclic.
Maintenant, dans le controler, event global left pressed (cet event a lieu lors de n'importe quel clic dans la room):
if (oclic!=noone)&&(mouse_x>100)&&(mouse_x<100+80*8)&&(mouse_y100)

     {
     locx=floor((oclic.x-100)/80);locy=floor((oclic.y-100)/80);
     cibx=floor((mouse_x-100)/80);
     ciby=floor((mouse_y-100)/80);
     if object_index.oclic==j_pion
          {

          tst=script_execute(check_line,locx,locy,cibx,ciby,o_piece);
          if tst==0
                {

                if (locy==6)&&(locy-ciby>0)&&(locx==cibx)&&(locy-ciby<3)
                      {oclic.x=cibx*80+100;oclic.y=ciby*80+100;oclic=noone;}
                else if (locy-ciby==1)&&(locx==cibx)
                      {oclic.x=cibx*80+100;oclic.y=ciby*80+100;oclic=noone;}}}}


La première ligne conditionnelle vérifie qu'un objet a été sélectionné, et que les coordonnées du nouveau clic sont sur l'échiquier. locx... font correspondre les coordonnées sur l'écran à des cases du plateau, de la position de base de la pièce à l'endroit où le joueur a cliqué. La condition suivante s'occupe du cas spécifique du pion, la fonction object_index renvoie l'index d'objet de l'instance qui doit être égal au nom donné à l'objet "pion du joueur". Ensuite, une fonction utilisateur est appelée, il faudra créer ce script par la suite, qui aura pour but de vérifier qu'il n'y a pas de pièce entre le pion et sa case de destination, et qui pourra être utilisé aussi pour les tours et la reine. Cette fonction renvoiera 0 si aucune pièce n'est rencontrée, 1 si la case de destination est occupée par une pièce adverse et qu'il n'y a aucune pièce entre les deux, et 2 si il y a une pièce entre les deux cases ou que la case de destination est occupée par le même joueur. On vérifie ceci en testant la variable "tst", puis on examine deux cas: Soit le pion est sur sa case de départ, soit y=6 si je ne me suis pas trompé, et on autorise un clic jusqu'à deux cases, soit on autorise un clic à une case seulement. Il faut vérifier aussi que le pion ne va pas en arrière et qu'il se déplace sur sa ligne.

Le script "check_line" recevra en argument les coordonnées des deux cases à tester, plus l'objet parent à considérer comme adversaire, "regardera" si aucune pièce ne se situe entre les deux, auquel cas il retournera 2. Si c'est la case de destination qui est occupée par un adversaire, le script retroune 1 (cas d'une prise). Enfin, si rien n'est rencontré, le script retourne 0. Il faut bien sûr d'abord créer un nouveau script et le nommer. Attention, il faut impérativement mettre en premier les coordonnées de la pièce à déplacer.
if (argument0!=argument2)&&(argument1!=argument3)
      {return 2}
if (argument0==argument2)&&(argument1>argument3)
      {

      for(i=argument1-1;i>argument3-1;i-=1)
           {

           if instance_position(i*80+100,argument0*80+100,all)!=noone
                 {

                 if i>argument3

                      {return 2;}

                 else if (i==argument3)&&(instance_position(i*80+100,argument0*80+100,argument4)!=noone)

                      {return 1;}

                 else

                      {return 2;}}}}
if (argument0==argument2)&&(argument3>argument1)
      {

      for(i=argument1+1;i<argument3+1;i+=1)
           {

           if instance_position(i*80+100,argument0*80+100,all)!=noone

                {
                if i<argument3

                      {return 2;}

                 else if (i==argument3)&&(instance_position(i*80+100,argument0*80+100,argument4)!=noone)

                      {return 1;}

                 else

                      {return 2;}}}}
if (argument1==argument3)&&(argument0>argument2)
       {

       for(i=argument0-1;i>argument2-1;i-=1)
            {

            if instance_position(argument1*80+100,i*80+100,all)!=noone

                 {
                 if i>argument2

                      {return 2;}

                 else if (i==argument2)&&(instance_position(argument1*80+100,i*80+100,argument4)!=noone)

                      {return 1;}

                 else

                      {return 2;}}}}
if (argument1==argument3)&&(argument0<argument2)
      {

      for(i=argument0+1;i<argument2+1;i+=1)
           {

           if instance_position(argument1*80+100,i*80+100,all)!=noone

                {
                if i<argument2

                      {return 2;}

                else if (i==argument2)&&(instance_position(argument1*80+100,i*80+100,argument4)!=noone)

                      {return 1;}

                else

                      {return 2;}}}}
return 0;
Ainsi la première condition vérifie d'abord que les deux cases à tester sont en ligne, sinon le script retourne false. Notons que la fonction return interrompt le script et donne la variable à droite de return comme valeur retour.
Ensuite il faut tester quelle est la valeur la plus grande entre les coordonnées des cases pour savoir dans quel ordre faire tourner la boucle, et quelle ligne est considérée: horizontale ou verticale? Tout cela pour vérifier que les cases appropriées sont vides.

Pions: prise en diagonale.

Il faut rajouter avant tst=script_execute...

if (cibx==lox-1)&&(locx-1>=0)&&(ciby==locy-1)&&(locy-1>0)&&(instance_position(cibx,ciby,o_piece)!=noone)

      {

      position_destroy(cibx,ciby,all);

      oclic.x=cibx*80+100;oclic.y=ciby*80+100;oclic=noone;

      }

if (cibx==lox+1)&&(locx+1<=7)&&(ciby==locy-1)&&(locy-1>0)&&(instance_position(cibx,ciby,o_piece)!=noone)

      {

      position_destroy(cibx,ciby,all);

      oclic.x=cibx*80+100;oclic.y=ciby*80+100;oclic=noone;

      }

position_destroy sert à supprimer les instances d'objets dont la sprite couvre la position indiquée.

 

Publicité
Publicité
12 janvier 2012

GM présentation générale

 

Game Maker permet de créer des jeux vidéos, plutôt en 2D.
Son fonctionnement tourne autour de la création d'objets, et d'events pour ceux-ci. Les events sont les conditions à partir desquelles telle action ou tel script sont effectués, comme un clic sur l'objet...
Mais tout d'abord, pour qu'un objet soit visible ingame, il faut lui associer une sprite, préalablement dessinée ou téléchargée: ce sera son aspect. Ensuite, il faut créer une nouvelle room, dans la liste adéquate, choisir l'objet défini dans la liste des objets à poser et cliquer quelque part dans la room. A partir de ce point, lançant le jeu, on peut voir l'objet défini là où on l'a placé.

Plus généralement, le jeu obéit à des règles précises. A son lancement, il charge les instances d'objets présents dans la room. Les instances d'objets sont simplement les représentants de l'objet de référence. Pour qu'elles soient différenciées le moteur attribue une id différente à chaque instance de l'objet. Si les objets ont un creation code (qu'on peut ajouter par le biais d'un event), il est exécuté ainsi que leur game-start event. Ensuite le creation code (qu'on peut définir dans l'onglet settings des room) de la starting room (la room qui a cette option cochée est celle de départ) est chargé. Enfin, l'event room start des objets a lieu.
Il est aussi important de savoir l'ordre dans lequel les events ont lieu, c'est indiqué dans la rubrique "events" de l'aide. Globalement, il y a les events de type step, qui sont réalisés continuellement, et ceux généralement plus ponctuels d'intéraction du joueur, mais attention, ils peuvent être réalisés aussi en boucle selon le type d'event choisi (tant qu'une touche est pressée par exemple). En dernier lieu, il y a l'event draw qui est le seul à pouvoir afficher des choses sur l'écran. Sa particularité est "d'effacer" la sprite de l'objet où il est défini, aussi si on veut que l'objet soit visible, il faut le préciser dans le code. Mais on assigne généralement les actions de dessin à un controleur de jeu, qui n'a pas besoin d'être sur l'écran. L'event draw est aussi réalisé en boucle. Il faut veiller à ne pas mettre des scripts trop gourmands en ressources dans ce genre de cas.

Publicité
Publicité
deshayesdivers
Publicité
Archives
Publicité