Les Cartes

La dernière fois nous avons réglé l'attaque de nos différents personnages. Mais comme dit dans les règles nous possèderont différentes unités, ainsi que des cartes sorts, bâtiment ... Il nous faut donc un moyen de choisir au préalable nos cartes afin de créer un paquet de cartes. Puis nous verrons comment mélanger aléatoirement notre paquet de cartes.

Pour commencer, il nous faut définir nos cartes, pour cela nous créer une instance d'objet appelé Carte.

class Carte{
int xposition;
int yposition;
int Cout1;
int Cout2;
PImage icon;
int xtaille_unit;
int ytaille_unit;
int VieMax;
int Vit;
String Portee;
int att;
int def;
String Faction;
String Type;
String Nom;
PImage Icon_unit;

Sur toute ces variables et objets seul 3 concerne directement la carte en question. Les variables de positions en x et en y afin d'afficher la carte dans une interface, et l'objet image icon qui correspond à l'image de la carte.

Toute les autre variable et objet sont destiné à l'unité ou les futurs sort utilisé.

Donc maintenant que l'instance d'objet est créer, créons nos carte via des tableaux. Comme dit dans les règles du jeu, nous avons besoin en tout de 9 tableaux auxquels j'en rajoute 1 pour la suite. Pour récapituler les tableaux, deux pour chaque joueurs : un pour la pioche et un pour la main. Pour chacun de ces 4 tableaux d'objet carte je rajoute un tableau booléen de même longueur. Ensuite un tableau qui sert de glossaire de toute les cartes existantes. Ensuite le dernier tableaux (de valeur entière) nous sert d'intermédiaire lors de la sélection de carte.

Sélection de Menu:

Pour pouvoir choisir nos cartes, il nous faut d'abord mettre en pause l'ancienne partie déjà codée. Chose très simple j'utilise une variable que j'appelle histoire. Dans la fonction draw(), je crée deux condition : si la variable histoire est égale à 1 alors ... (ici on englobe tout ce qui est relatif à la sélection de carte); si la variable histoire est égale à 2 alors ...(ici on englobe tout ce qui ce rapporte à la partie de jeu).

Sélection de Carte:

Pour notre sélection de carte nous avons besoin d'aux moins 2 cartes (définie dans le tableau glossaire) qui serviront de test à notre code :

Glossaire[0]= new Carte(0,0, taille,taille, 1,0, 3,4, 2,0,"1", TICarte[1], "Mort-Vivant", "Unite", "Guerrier Squelette",IconUnite[0]);

Glossaire[1]= new Carte(0,0, taille,taille, 2,0, 2,4, 2,0,"2", TICarte[2], "Mort-Vivant", "Unite", "Archer Squelette",IconUnite[1]);

Pour définir une carte dans le glossaire on fait appel au constructeur de l'objet carte et rien de plus :

Carte(int Nxposition, int Nyposition, int Nxtaille_unit, int Nytaille_unit, int NCout1, int NCout2, int NVieMax, int NVit, int Natt, int Ndef, String NPortee, PImage Nicon, String NFaction, String NType, String NNom, PImage NIcon_unit){

Sélection de Cartes :

Etant donné qu'il existera plusieurs paquet de cartes différents à l'avenir, je crée un simple menu avec des icons correspondant à la faction du paquet de cartes en question. Pour l'instant il n'y a q'une seule possibilité celui de la faction mort-vivante. En cliquant sur l'icon on arrive donc sur la sélection de carte.

Il nous faut d'abord définir les différentes variable et objet : -On reprend d'abord nos tableaux de cartes créés précédemment auquel on rajoute la variable CarteRestante, tout est dit dans son nom pas besoin d'explication et un tableau d'entier NmbCarte_DebutDeck. -Après on a besoin de la variable PCamera (position caméra) ainsi que de Ress1, Ress2, Faction_Deck (pour savoir qu'elle partie du glossaire à afficher), et ChFaction (qui sert lors de l'initialisation d'un Joueur). -Nous avons aussi besoin d'une variable (Random) et d'un tableaux d'entier (Elimine) pour mélanger notre paquet de cartes ainsi que de deux autres variable : Actuel_Carte et Position.

Maintenant que nous avons sélectionné notre faction et que nous avons toute nos variables/objet/etc, il faut afficher les différentes cartes.

for(int C=0; C<Glossaire.length; C++){

image(Glossaire[C].icon, 50+300*(C-Pcamera),20,250,400);

image(TflecheDirectionnel[1], 70+300*(C-Pcamera),440,48,48);

image(TflecheDirectionnel[3], 235+300*(C-Pcamera),440,48,48);

text(NmbCarte_DebutDeck[C],165+300*(C-Pcamera),475);

On lance donc une boucle pour chaque carte du glossaire. A chaque boucle, on affiche la carte (avec toute ses caractéristiques), ensuite on affiche en-dessous 2 flèches opposée l'une à l'autre et entre les deux, on affiche la valeur du tableau NmbCarte_DebutDeck à la case égale à C, valeur correspondant au nombre de fois que l'on a sélectionné cet carte. En multipliant par C la position x des images on obtient un défilement horizontale des cartes, c'est bien mais si on a trop de carte, elles sortent de l'écran. On soustrait donc à C la valeur de Pcamera, une valeur qui varie en fonction des touches droite et gauche. De la sorte on a un défilé de carte que l'on peut parcourir très simplement.

Maintenant il nous faut sélectionner les cartes. Nous avons donc 2 possibilité : "le Joueur clique sur la flèche de gauche, donc la valeur de NmbCarte_DebutDeck diminue, on enlève une carte de la sélection". Et la possibilité inverse "le Joueur clique sur la flèche de droite, donc la valeur de NmbCarte_DebutDeck augmente, on rajoute une carte à la sélection".

Commençons par la seconde probabilité.

//Flèche de Droite////Additionne//

if(mouseX>=235+300*(C-Pcamera) && mouseX<=235+48+300*(C-Pcamera) && mouseY>=440 && mouseY<=440+48){

image(TflecheDirectionnel[7], 235+300*C,440,48,48);

if(mousePressed==true){

NmbCarte_DebutDeck[C]++;

Limit_ChoixDeck++;

if(Limit_ChoixDeck>Limit_deck){

NmbCarte_DebutDeck[C]=NmbCarte_DebutDeck[C]-1;

Limit_ChoixDeck--; }

mousePressed=false; } }

On commence donc par la condition, si la souris se trouvent aux coordonnées de l'image, alors changé l'image, et si la souris est pressée alors : On augmente la valeur de NmbCarte_DebutDeck à la case C de un cran, pareil pour limit_ChoixDeck (variable enregistrant le nombre de carte sélectionné). Puis on cherche à savoir si l'on dépasse le nombre de carte sélectionné, si c'est le cas on annule l'action précédente.

Ensuite la deuxième possibilité, la flèche gauche :

//Flèche De Gauche////Soustrait//

if(mouseX>=70+300*(C-Pcamera) && mouseX<=70+48+300*(C-Pcamera) && mouseY>=440 && mouseY<=440+48){

image(TflecheDirectionnel[5], 70+300*C,440,48,48);

if(mousePressed==true){

NmbCarte_DebutDeck[C]--;

Limit_ChoixDeck--;

if(NmbCarte_DebutDeck[C]<0){

NmbCarte_DebutDeck[C]=0;

Limit_ChoixDeck++; }

mousePressed=false; } }

Ici même raisonnement, on procède juste de la manière inverse.

Quand le joueur a fini, il va devoir confirmé en appuyant sur entrée puis le programme mélange son paquet de cartes, initialise le joueur (base, ressource, etc). 

 Prenons l'exemple du joueur 1.

if(tour==0){

///Joueur 1///////////////////////////////////////////////////////////////////////////////////////////////

Base[0]= new Commandant(taille*0,taille*6, Ress1,Ress2, ChFaction, 15);

Base[0].J=1;

for(int i=0; i<NmbCarte_DebutDeck.length; i++){

for(int N=0; N<NmbCarte_DebutDeck[i]; N++){

Deck_En_Cour[Position]=Glossaire[i];

Position++; } }

for(int i=0; i<Elimine.length; i++){

Elimine[i]=-1; }

for(int D=0; D<Deck_JI.length; D++){

Actuel_Carte=D;

Random();

Deck_JI[Actuel_Carte]=Deck_En_Cour[Random];

DeckV1[Actuel_Carte]=true;

Elimine[Actuel_Carte]=Random; }

for(int D=0; D<Limit_Main; D++){

tour=1;

Deck(); }

tour=2;

keyPressed=false;

Faction_Deck=0;

for(int i=0; i<NmbCarte_DebutDeck.length; i++){

NmbCarte_DebutDeck[i]=0; }

Limit_ChoixDeck=0; }

On commence par savoir si c'est bien la sélection du Joueur 1 par la variable tour. Ensuite on initialise la base du joueur (objet regroupant les ressources et le QG du Joueur). On lance deux boucle, une boucle de la longueur du tableaux NmbCarte_DebutDeck puis une seconde de la longueur de la valeur de la case égale à i. Ces deux boucles nous permettent de remplir le tableau d'objet carte intermédiaire seulement avec les cartes choisie et ceux sans parasite.

Après on a une boucle qui ne sert qu'à éviter de potentiel bug (pas forcément utile pour le joueur 1 mais essentiel pour le joueur 2). Cette boucle consiste donc à initialiser toute les cases du tableaux Elimine sur -1 (vous comprendrais plus tard pourquoi c'est nécessaire).

On passe enfin au mélange du paquet de carte avec la boucle suivante. On commence par affecté la valeur de D à Actuel_Carte (utile car on je dois faire appel à d'autre fonction indépendante), on fait un appel de la fonction Random() (fonction nous permettant d'avoir un nombre aléatoire non tiré précédemment). On affecte donc le paquet de carte avec une carte aléatoire du tableaux d'objet carte intermédiaire on considère cette carte comme active puis la valeur Random est enregistrer dans le tableau Elimine. Avec ce processus on range donc toute les cartes choisies précédemment dans le paquet de carte d'un joueur tout en le mélangeant. Ci-dessous, la fonction Random() :

void Random(){

Random=int(random(0,Limit_deck));

for(int E=0; E<Elimine.length; E++){

if(Random==Elimine[E]){

Random(); } } }

Dans la fonction, on affecte donc une valeur aléatoire à Random, puis on compare cette valeur à toute les autres du tableaux Elimine, si l'une des valeurs est la même on rappel la fonction Random() par récurrence. De la sorte on est sur que la valeur de Random est aléatoire est non sortie précédemment.

La boucle suivante concerne la main du Joueur, on demande à l'ordi via la fonction deck() de tirer une carte en fonction du paquet de carte du joueur et ce 5x.

void Deck(){
pioche=1;
if(tour==1){
for(int C=0; C<Limit_Main; C++){
if(MainV1[C]==false && pioche>=1){
Main_JI[C]=Deck_JI[DeckPost_JI];
DeckPost_JI++;
pioche--;
MainV1[C]=true;
if(DeckPost_JI>=Deck_JI.length){
Melange(); } } }
tour=1.1;}

Pour la fonction deck() on utilise une variable pioche qu'on affecte à la valeur 1. Puis on vérifie le tour (1=Joueur1 et 2=Joueur2), on débute alors une boucle de la longueur de la main. On vérifie à chaque boucle si la carte de la main à cette position est absente et si la variable pioche est supérieur ou égale à 1. Si c'est le cas alors, on affecte à la main la carte à la case égale à DeckPost_JI (Position dans le paquet du Joueur 1), variable augmentant d'un cran à chaque tirage. De la sorte, chaque carte du paquet est tiré l'une après l'autre. Si l'on arrive au bout du paquet, on appel la fonction Melange() qui agit de la même manière que lorsqu'on à mélanger le paquet au début.

On revient à notre sélection avec les dernières lignes de Code :

tour=2;
keyPressed=false;
Faction_Deck=0;
for(int i=0; i<NmbCarte_DebutDeck.length; i++){
NmbCarte_DebutDeck[i]=0;
}
Limit_ChoixDeck=0;

On change donc le tour pour passer au Joueur 2, on affecte false à la variable booléenne keyPressed afin d'éviter des bugs. Puis on remet les valeurs de base du menu de sélection de carte afin de passer au Joueur 2.

A savoir, pour le Joueur 2, on met juste :

Histoire=2;
tour=1.2;

On change de tour (Joueur 1) et de scène (par la variable histoire).




La main d'un Joueur :

Nous avons une pioche et une main pour chaque Joueur mais il nous ne pouvons pas encore jouer les différentes cartes. Il nous faut donc afficher la main puis pouvoir sélectionner une de ces cartes.

Pour afficher la main rien de plus simple, dans la partie interface de l'écran de jeu (actuellement à gauche du terrain), Je place un icon qui sert à afficher ou masquer la main du Joueur.

Pour la main en question, on utilise la fonction Main() :

void Main(){
if(AfficheMain==true){
if(tour>=1.1 && tour<2){
for(int C=0; C<Limit_Main; C++){
if(MainV1[C]==true){
image(Main_JI[C].icon,taille*6*C+(taille/4)*C,taille*3,taille*6,taille*10);
if(mouseX>=taille*6*C+(taille/4)*C && mouseX<=taille*6*C+(taille/4)*C+taille*6){
if(mouseY>=taille*3 && mouseY<=taille*3+taille*10){
noFill();
stroke(150,150,0);
strokeWeight(10);
rect(taille*6*C+(taille/4)*C,taille*3,taille*6,taille*10);

Première condition, si on appuyait précédemment sur l'icon qui affiche la main. La seconde condition cherche qui joue (ici le joueur 1). Puis on débute une boucle de la longueur de la main (5 carte). On cherche à chaque boucle si à cet emplacement de la main il y a une carte valide, si c'est le cas, on affiche la carte. On compare ensuite les coordonnées de la souris à celle de la carte, si les coordonnées de la souris sont comprise dans celle de la carte alors on affiche un rectangle vide mais au contour grossit et de couleur jaune autour de la carte.

Après on effectue une condition si la souris est pressé alors... et c'est là qu'on s'amuse.





Commençons avec le 1er cas, la carte est une unité.

if(mousePressed==true){
if(Base[0].RessI-Main_JI[C].Cout1>=0 && Base[0].RessII-Main_JI[C].Cout2>=0){
/////Unité/////
if(Main_JI[C].Type=="Unite"){
Tunite_JI[NmbUnite1]= new Unite(/*Position*/taille*3,taille*7,/*taille* /Main_JI[C].xtaille_unit,Main_JI[C].xtaille_unit,/*Vie*/Main_JI[C].VieMax,/*Vitesse*/Main_JI[C].Vit,/*Stats*/Main_JI[C].att,Main_JI[C].def,/*Portee*/Main_JI[C].Portee,Main_JI[C].Icon_unit, Main_JI[C].Type, Main_JI[C].Nom, 1);
TuniteVivant_JI[NmbUnite1]= true;
NmbUnite1++;
if(NmbUnite1>=limite_d_unit){
NmbUnite1=0; } }

On cherche avant tout à savoir si le joueur a assez de ressources pour jouer la carte. Puis on cherche à savoir le type de carte (Pour rappel il y a 4 type Unité/Sort/Bâtiment/Amélioration). Si la carte est une unité alors : Créer dans le tableau Tunite_JI, à la case NmbUnite1, une unité avec les caractéristique de la carte. Puis on active cet unité dans le tableau booléenTuniteVivant_JI. On augmente par la suite la valeur de NmbUnite1 afin de ne pas avoir deux unité pour la même case sans oublier de vérifier que cette valeur ne dépasse pas la longueur de nos deux tableaux précedent.




On passe maintenant au sort :

/////Sort/////
if(Main_JI[C].Type=="Sort"){
if(Main_JI[C].Nom=="Fauchage"){
Fauchage();
}
if(Main_JI[C].Nom=="Récolte d'Os"){
RecolteAct=true;
action=1;
}

Donc on recherche encore le type de la carte, mais on rajoute une autre condition, le nom de la carte afin de savoir quel sort il faut activer. On a ici deux types de sort, le premier à effet immédiat (où l'on fait un bête appel de fonction) et le deuxième à effet "retarder" c'est à dire que le joueur doit choisir une case précise (là on active une variable qui va activer une fonction lié au sort, cela permet que le draw répète la fonction laissant le Joueur choisir la case voulue (effet non possible avec un bête appel de fonction) ).





On passe au bâtiment : (à savoir: les bâtiments sont des objets ressemblant fortement aux unités).

/////Batiment/////
if(Main_JI[C].Type=="Batiment"){
if(Main_JI[C].Nom=="Ferme à Charnier"){
ConstAct=true;
action=1;
}
}

Même principe que les sort à effet "retardé". Mais je vous détaille quand même la fonction construction :

void Construc(){
for(int C=0; C<Emplacement.length; C++){
if(C+1<300 && C+20<300 && C+21<300){
if(mouseX>=Emplacement[C].xposition && mouseX<=Emplacement[C].xposition+taille && mouseY>=Emplacement[C].yposition && mouseY<=Emplacement[C].yposition+taille){
fill(150,150,0,63);
strokeWeight(4);
stroke(150,150,0);
rect(Emplacement[C].xposition,Emplacement[C].yposition,taille*2,taille*2);
if(mousePressed==true){
if(tour>=1 && tour<2){
Batiment_JI[NmbBatiment1]=new Batisse(Emplacement[C].xposition,Emplacement[C].yposition, 10, 1, IBatiment[1], "Ferme à Charnier", 1, 2);
BatimentVivant_JI[NmbBatiment1]=true;
NmbBatiment1++;
}
if(tour>=2 && tour<3){
Batiment_JII[NmbBatiment2]=new Batisse(Emplacement[C].xposition,Emplacement[C].yposition, 10, 1, IBatiment[1], "Ferme à Charnier", 2, 2);
BatimentVivant_JII[NmbBatiment2]=true;
NmbBatiment2++;
}
Emplacement[C].Tas_d_os=0;
ConstAct=false;
action=0; } } } } }

Pour la fonction, on lance une boucle pour chaque case du terrain, on cherche (pour un bâtiment de dimension 2*2) si toute les case sont sur le terrain et non en-dehors, puis on compare les coordonnées de la souris à la case de la boucle actuelle, si les coordonnées sont similaires, on affiche un rectangle jaune sur les case où seras construit le bâtiment. On cherche ensuite si la souris est pressée, on crée alors en conséquence le bâtiment (ici il n'y a qu'un seul bâtiment disponible pour l'instant). Attention, ne pas oublier de vérifie le tour de jeu afin de bien attribuer le bâtiment à un Joueur. Le processus pour créer un bâtiment est le même que pour créer une unité. Après la création du bâtiment, on supprime les potentiels tas d'os des cases, on annule la phase de construction est on remet la variable action à 0.

A savoir, pour les sorts, le principe est le même à quelque ligne prêt.

J'en profite pour faire un aparté sur le ciblage du bâtiment lors d'une attaque :

if(U_Att<limite_d_unit && Emplacement[C_Deff].Presence=="Batiment 2"){

for(int B=0; B<Batiment_JII.length; B++){

if(BatimentVivant_JII[B]==true){

for(int X=0; X<taille*2; X+=taille){

for(int Y=0; Y<taille*2; Y+=taille){

if(Emplacement[C_Deff].xposition==Batiment_JII[B].xperso+X && Emplacement[C_Deff].yposition==Batiment_JII[B].yperso+Y){

Degat=int(Tunite_JI[U_Att].att-Batiment_JII[B].def);

if(Degat<=0){

Degat=1;}

Batiment_JII[B].Vie-=Degat;

action=0;

Tunite_JI[U_Att].Phase_Perso=0;

Tunite_JI[U_Att].mouvement=0; } } } } } }

Cet partie se situe dans la fonction degat() que nous avons précédemment utilisé pour attaquer avec les unités. Le principe est exactement le même, sauf que lorsque l'on cherche si le bâtiment est sur la case ciblée, on fait le test sur toute les cases que le bâtiment occupe (ici 4 au lieu de 1 pour les unités).





On passe maintenant aux amélioration :

/////Amélioration/////
if(Main_JI[C].Type=="Amélioration"){
if(Main_JI[C].Nom=="Boyau Ferme"){
Boyau1=3;
BoyAct1=true;
}

Donc le principe est le même que les batiments et les sorts mais aux lieu de changer la valeur de la variable action (qui nous permettait de ne pas avoir d'action en simultané) on change un valeur lié à l'amélioration elle même : cet variable corespond au délai d'activation de l'amélioration. Mais penchons nous un peu sur ce qui se passe à la fin du délai

void Project_Acide(){
textSize(20);
fill(255);
if(ProjAcide_Act1==true){
if(tour>=1 && tour<2){
if(ProjAcide1>0){
text("Projection Acide dans "+ProjAcide1+" tour",taille*23.5,taille*4.75); }
if(ProjAcide1==0){
for(int C=0; C<Limit_deck; C++){
if(Deck_JI[C].Nom=="Zombie"){
if(Deck_JI[C].J==1){
Deck_JI[C].Portee="1-2";
}
}
}
for(int U=0; U<Tunite_JI.length; U++){
if(TuniteVivant_JI[U]==true){
if(Tunite_JI[U].Nom=="Zombie"){
Tunite_JI[U].portee="1-2"; } } } } } }

On a donc un fonction pour chaque amélioration (ici on a mis que la partie de la fonction sur le Joueur 1). Chaque fonction commence par la condition si la variable booléenne lié à ce joueur pour cet amélioration est vrai alors... Puis on cherche à savoir qui joue. Si c'est au Joueur 1 alors est que le délai est actif alors affiché le nom de l'amélioration et le nombre de tour restant. Par contre si le délai est fini alors, affecté l'amélioration à toute les cartes de jeu du Joueur puis affecté l'amélioration à toute ces unités sur le terrain (ici l'amélioration consiste à une augmentation de la portée des unité zombies, on cherchent donc à savoir si la carte ou l'unite en question est un zombie, si c'est le cas on change la valeur de portee en "1-2").

Donc maintenant que la carte a été jouée, il faut remettre le jeu à "la normale" :

AfficheMain=false;

mousePressed=false;

Base[0].RessI-=Main_JI[C].Cout1;

Base[0].RessII-=Main_JI[C].Cout2;

MainV1[C]=false;

On règle la variable booléenne AfficheMain sur faux afin d'enlever les cartes de notre vue, la souris est désélectionné, on applique le coût de la carte sur les ressources du joueur, puis on désactive la carte de sorte à ce qu'elle ne soit plus rejouée.

Créez votre site web gratuitement ! Ce site internet a été réalisé avec Webnode. Créez le votre gratuitement aujourd'hui ! Commencer