oui mais cela voudrais dire qu'il peut sortir par n'importe quel endroit de la map donc pour contrôler le changement de map cela deviendrait peut-être plus complexe car il pourrait sortir par en haut comme en bas comme à droite ou encore à gauche
oui mais cela voudrais dire qu'il peut sortir par n'importe quel endroit de la map donc pour contrôler le changement de map cela deviendrait peut-être plus complexe car il pourrait sortir par en haut comme en bas comme à droite ou encore à gauche
En effet. Si ça te fait peur, on peut garder les téléporteurs pour l'instant. Dans ce cas, il faut pouvoir en avoir plusieurs par map.
Ensuite, pour savoir quel téléporteur est le bon, deux solutions: Soit les numéroter, soit les connaître uniquement par leurs coordonnées.
Ce qui veut déjà dire que ta map doit être plus complexe qu'un simple tableau 2D: Il nous faut une structure à présent:
Code C : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 struct SWarp { /*ici les coord de départ sur la map courante*/ int sourceX; int sourceY; /*Ici, l'identification de la map de sortie: nom, coordonnées, etc.*/ int destMapX; int destMapY; /*ici les coordonnees d'arrive sur la map de sortie*/ int destX; int destY; } struct SMap { char tiles[10][20]; struct SWarp warps[8]; char titre[32]; };
Code C : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 struct SMap allMaps[2] = { /*Salle (0; 0)*/ { { "###################", "#@ #", "# #", "# #", "# #", "# : #", "# :", "# + #", "# #", "###################" }, { { 5, 5, ??, ??, ??, ?? }, /*Je ne sais pas où ça mène*/ { 19, 6, 1, 0, 0, 6 } /*La porte à droite*/ }, "Cuisine Ouest" }, /*Salle (1; 0)*/ { { "###################", "# #", "# #", "# #", "# + #", "# #", ": #", "# #", "# #", "###################" }, { { 0, 6, 0, 0, 19, 6 } /*La porte à gauche*/ }, "Cellier Est" };
SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.
"Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
Apparently everyone. -- Raymond Chen.
Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.
Bon je vais me plonger dans le code et reviendrai vers vous si je ne comprends pas tout car à première vue je vois un peu mais il me reste des points d’interrogation en tout cas merci pour cette réponse
Note que le champ titre n'est pas un champ nom. Sa valeur est uniquement vouée à être affichée, surtout pas à être utilisée en interne pour identifier la map. Si on veut identifier une map par son nom plutôt que ses coordonnées, il faudra lui donner un champ nom séparé.
SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.
"Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
Apparently everyone. -- Raymond Chen.
Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.
Alors voila j'ai deux questions peut-être bête je ne sais pas :
1erpourquoi 1; 0 et non pas 0; 1 ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part /*Salle (1; 0)*/
2emequand il tombe sur ça l’interprète t-il ou pas ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 { 5, 5, ??, ??, ??, ?? }, /*Je ne sais pas où ça mène*/ { 19, 6, 1, 0, 0, 6 } /*La porte à droite*/
quelques remarques:
- tu ne devrais pas itérer sur toutes les cases d'une map pour trouver le joueur, tu peux stocker sa position. (Et si d'autres entités doivent bouger, tu peux stocker leurs position aussi.)
- vu que tu bosses avec un affichage console pour le moment, tu devrais éviter de redessiner la map pour rien (quand rien ne bouge), ça évitera des scintillements.
- utilise une enum pour différencier tes tiles.
ça t'évitera des erreurs du à des fautes de frappes et rendra le code plus clair. Tu auras juste à "convertir" ça lors de l'affichage, par exemple avec une fonction du style
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 enum TileType { TT_EMPTY, TT_PLAYER, TT_WARP, etc... };
edit:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 inline char charFromTile(TileType tp) { switch(tp) { case TT_EMPTY: return ' '; case TT_PLAYER: return '@'; etc.. }
Si tu te poses la question des "??", non, c'est à toi de les remplacer par les bonnes valeurs
Donc si je te suis bien quand je vais déplacer le joueur sur la case et que le programme va voir celail va interpréter toute les informations et changer de map
Code : Sélectionner tout - Visualiser dans une fenêtre à part { 19, 6, 1, 0, 0, 6 } /*La porte à droite*/
bon alors je suis parti sur la structure de médinocmais une chose reste en parti un peu flou donc si quelqu'un peu m'expliquer cela serai merveilleux. la parti flou est le changement de map je comprend pas tout ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56 struct SWarp { /*ici les coord de départ sur la map courante*/ int sourceX; int sourceY; /*ici, l'identification de la map de sortie: nom, coordonnées, etc.*/ int destMapX; int destMapY; /*ici les coordonnees d'arrive sur la map de sortie*/ int destX; int destY; }; struct SMap { char tiles[10][20]; struct SWarp warps[8]; char titre[32]; }; struct SMap allMaps[2] = { /*Salle (0; 0)*/ { { "###################", "#@ #", "# #", "# #", "# #", "# #", "# :", "# + #", "# #", "###################" }, { //{ 5, 5, ??, ??, ??, ?? }, /*Je ne sais pas où ça mène*/ { 19, 6, 1, 0, 0, 6 } /*La porte à droite*/ }, "Cuisine Ouest" }, /*Salle (1; 0)*/ { { "###################", "# #", "# #", "# #", "# + #", "# #", ": #", "# #", "# #", "###################" }, { { 0, 6, 0, 0, 19, 6 } /*La porte à gauche*/ }, "Cellier Est" } };
edit : alors j'ai bidouiller un peu pour faire en sorte d'utiliser la structure et voila le codeseul petit bémol il ne change pas de map va savoir pourquoi je travail encore dessus n'hesiter pas a me dire si vous avez la raison du pourquoi merci
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156 #include <iostream> #include <windows.h> using namespace std; struct SWarp { /*ici les coord de départ sur la map courante*/ int sourceX; int sourceY; /*ici, l'identification de la map de sortie: nom, coordonnées, etc.*/ int destMapX; int destMapY; /*ici les coordonnees d'arrive sur la map de sortie*/ int destX; int destY; }; struct SMap { char tiles[10][20]; struct SWarp warps[8]; char titre[32]; }; struct SMap allMaps[2] = { /*Salle (0; 0)*/ { { "###################", "#@ #", "# #", "# #", "# #", "# #", "# :", "# + #", "# #", "###################" }, { //{ 5, 5, ??, ??, ??, ?? }, /*Je ne sais pas où ça mène*/ { 19, 6, 1, 0, 0, 6 } /*La porte à droite*/ }, "Cuisine Ouest" }, /*Salle (1; 0)*/ { { "###################", "# #", "# #", "# #", "# + #", "# #", ": #", "# #", "# #", "###################" }, { { 0, 6, 0, 0, 19, 6 } /*La porte à gauche*/ }, "Cellier Est" } }; bool Exit = false; int inmap = 0; int gamespeed = 200; int main() { int y, y2, x, x2; while(Exit == false) { system("cls"); for(y = 0; y < 10; y++) { cout << allMaps[inmap].tiles[y] << endl ; } cout << allMaps[inmap].warps->sourceX << endl; for(y = 0; y < 10; y++) { for(x = 0; x < 20; x++) { switch(allMaps[inmap].tiles[y][x]) { case '@': { if(GetAsyncKeyState(VK_UP) != 0) { y2 = y - 1; switch(allMaps[inmap].tiles[y2][x]) { case ' ': allMaps[inmap].tiles[y][x] = ' '; y--; allMaps[inmap].tiles[y2][x] = '@'; break; } } if(GetAsyncKeyState(VK_DOWN) != 0) { y2 = y + 1; switch(allMaps[inmap].tiles[y2][x]) { case ' ': allMaps[inmap].tiles[y][x] = ' '; y++; allMaps[inmap].tiles[y2][x] = '@'; break; } } if(GetAsyncKeyState(VK_LEFT) != 0) { x2 = x - 1; switch(allMaps[inmap].tiles[y][x2]) { case ' ': allMaps[inmap].tiles[y][x] = ' '; x--; allMaps[inmap].tiles[y][x2] = '@'; break; case ':': inmap = allMaps[inmap].warps->destX; x = allMaps[inmap].warps->sourceX; y = allMaps[inmap].warps->sourceY; break; } } if(GetAsyncKeyState(VK_RIGHT) != 0) { x2 = x + 1; switch(allMaps[inmap].tiles[y][x2]) { case ' ': allMaps[inmap].tiles[y][x] = ' '; x++; allMaps[inmap].tiles[y][x2] = '@'; break; case ':': inmap = allMaps[inmap].warps->destX; x = allMaps[inmap].warps->sourceX; y = allMaps[inmap].warps->sourceY; break; } } } break; } } //Sleep(gamespeed); } } return 0; }
edit : non finalement erreur de ma part il change bien de map juste petit probleme a regler encore je tiens au courant
Salut,
D'abord, une petite correction...
Contrairement à C, lorsque tu définis une structure, une union, une énumération ou une classe en C++, tu déclare automatiquement un type dont l'identifiant est celui de la structure, de l'union, de l'énumération ou de la classe en question.
Il est donc tout à fait inutile de répéter le mot clé struct (ou enum, ou union ou encore class) lorsque tu veux utiliser le type en question comme membre d'une autre classe ou structure (ou union).
le codeserait donc avantageusement remplacé par
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 struct SMap { char tiles[10][20]; struct SWarp warps[8]; char titre[32]; };
et le code
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 struct SMap { char tiles[10][20]; SWarp warps[8]; char titre[32]; };
peut (doit ) s'écrire sous la forme de
Code : Sélectionner tout - Visualiser dans une fenêtre à part struct SMap allMaps[2] = { /*...*/
et, dans la même veine, tant qu'on y est:
Code : Sélectionner tout - Visualiser dans une fenêtre à part SMap allMaps[2] = { /*...*/
avec le code
tu force ta map à une taille fixe et définitive.
Code : Sélectionner tout - Visualiser dans une fenêtre à part char tiles[10][20];
Cela peut être une solution, mais je te donne mon billet qu'elle t'embêtera très rapidement, soit parce que tu voudra un jour créer un couloir de deux cases de large, soit parce que tu voudra un jour créer une "méga salle" de 20*40
L'idéal est sans doute de fournir une valeur pour le nombre de colonnes et une autre le nombre de lignes, et de travailler avec un tableau de (nombre de lignes * nombre de colonnes) éléments.
Il "suffit" de travailler avec la formule index = numéro de ligne * nombre de colonnes + numéro de colonnes pour récupérer l'index auquel correspond la case se trouvant à la ligne (numéro de ligne) et à la colonne (numéro de colonne).
Si tu travailles avec la classe vector, fournie par le standard dans l'espace de noms std par simple inclusion du fichier d'en-tête <vector>, tu auras l'occasion de travailler avec des map de n'importe quelle taille sans avoir à t'inquiéter de quoi que ce soit en terme d'espace mémoire dynamique
De même avec le code
tu force chaque map à avoir systématiquement 8 téléporteurs, ni moins, ni (et surtout pas!!!!) plus.
Code : Sélectionner tout - Visualiser dans une fenêtre à part SWarp warps[8];
Cela peut finir par poser quelques problèmes : certaines map ont peut etre des portes, mais pas de télé-porteurs du tout, et tu pourrais même envisager une "salle des télé-porteurs" qui te permet d'accéder à n'importe quelle map existante, ou que sais-je, mais qui nécessite d'avoir bien plus de 8 télé-porteurs
Encore une fois, le fait de pouvoir avoir "n'importe quel nombre de télé-porteurs" peut s'avérer intéressant, et la classe vector pourrait t'aider énormément à ce sujet
Enfin, la ligne
pose aussi problème, car elle place une limite tout à fait artificielle au nombre de caractères que tu peux afficher (en l’occurrence, 31 vu qu'il y a le '\0' terminal)
Code : Sélectionner tout - Visualiser dans une fenêtre à part char titre[32];
Encore une fois, le standard vient à ta rescousse en fournissant la classe string, disponible dans l'espace de noms std par simple inclusion du fichier <string> qui est la classe à préférer à toute autre solution pour représenter une chaine de caractères.
Au final, ta structure SMap devrait sans doute ressembler à quelque chose comme
En plus, le fait de coder les maps en "dur" (comprends: directement dans ton code) va te poser de très sérieux problèmes, dans le sens où tu devra systématiquement re compiler ton jeu chaque fois que tu voudra, par exemple, rajouter un mur ou une porte (et je ne te parle pas des problèmes que tu auras si tu veux carrément rajouter toute une map ).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 struct SMap { size_t rows; size_t cols std::vector<unsigned char> tiles; std::vector<SWrap> wraps; std::string title; /* et, comme on peut travailler en orienté objets, on peut rajouter * une fonction membre qui renvoie le caractère qui se trouve en X,Y ;) */ const unsigned char tileAt(size_t x, size_t y) const {return tiles_[y*cols + x];} /* et la même chose avec une Position (sait on jamais ;)) */ const unsigned char tileAt(Position const & pos) {return tileAt(pos.x(), pos.y());} };
L'idéal est donc de prévoir, dés le départ, la possibilité de gérer un nombre quelconque de maps de dimensions quelconques et composées d'un nombre quelconque de télé-porteurs et de portes, et surtout, de faire en sorte de ne pas avoir à recompiler ton jeu pour que les changements soient pris en compte.
Et pour cela, il n'y a pas 36 solutions : il faut passer par un (ou plusieurs) fichier(s) qui fournira (fourniront) toutes les indications que tu peux envisager.
Mais, pour cela, il faut réfléchir un peu à la manière dont on va fournir toutes les informations, pour pouvoir déterminer comment on peut les charger (et pourquoi pas, les sauvegarder, si d'aventure tu décide de créer un "éditeur de cartes" )
Le "monde" pourrait très bien etre subdivisé en différentes cartes selon un système proche de l'image ci-jointe sur laquelle chaque rectangle de couleur correspond à une carte particulière et les nombres séparés par des virgule (la première ligne dans chaque rectangle ) correspond aux coordonnées du coin supérieur gauche de la carte dans le monde. (Bon, ce n'est pas fait à l'échelle, mais ca te permettra de comprendre le principe )
Si tu associe pour chaque carte les coordonnées et un nom de fichier, tu peux charger une bonne fois pour toute une table d'équivalence entre les coordonnées et le fichier qui correspond à la carte à laquelle tu dois accéder.
Cela pourrait se faire avec un simple fichier texte proche de
world.txt(j'ai choisi des noms de fichiers correspondant aux couleurs employées, mais tu peux choisir n'importe quoi hein )
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 0 0 rouge.txt 25 0 jaune.txt 45 0 vert.txt 0 25 gris.txt 45 31 bleu.txt
Chaque fois que tu réduis l'espace où "vivent les koalas" en créant une carte supplémentaire, il te "suffit" de rajouter les coordonnées de son coin supérieur gauche et le nom du fichier qui en donne la description. Simple et efficace
Tu pourrait envisager charger cette liste sous la forme d'un
où la classe Position serait proche de
Code : Sélectionner tout - Visualiser dans une fenêtre à part std::map<Position, std::string> maplist;
Le chargement pourrait prendre la forme de
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 class Position { public: Position(int x, int y):x_(x), y_(y){} int x() const{return x_;} int y() const{return y_;} private: int x_; int y_; }; /* Pour pouvoir utiliser la std::map, on a besoin de l'opérateur de *comparaison < * */ bool oprtator <(Position const & first, Position const & second) { return first.x() < second.x() || (first.x() == second.x() && first.y() < second.y() ); } /* et, tant qu'à faire, te l'opérateur de comparaison == (pour d'autres * usages ultérieurs, très certainement ;) */ bool oprtator ==(Position const & first, Position const & second) { return first.x() == second.x() && first.y() == second.y() ); }
En fait, l'idée est simple: chaque fois que tu arrives sur un télé-porteur, tu cherches dans maplist (selon mon exemple) le nom du fichier qui correspond aux coordonnées destMapX et destMapY de la structure SWarp.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 void loadMapList(std::map<Position, std::string> & toFill) { std::ifstream ifs("world.txt"); int x; int y; std::string filename; while(ifs>>x>>y>>filename) { toFill.insert(std::make_pair(Position(x,y),filename); } } int main() { std::map<Position, std::string> maplist; loadMapList(maplist) ; /* tout le reste vient ici ;) */ return 0; }
Ce nom de fichier correspond au nom de fichier qu'il faut charger pour obtenir la carte en question
Evidemment, ca signifie que tu dois prévoir un format qui permette de représenter une carte.
Je te proposerais bien:
sur la première ligne, le nombre de lignes et le nombre de colonnes qui composent la carte, séparés par un espace
sur les (nombre de lignes) suivante, les (nombre de colonnes) qui correspondent à la topologie de la carte
juste après, nous aurions le nombre de télé-porteurs suivi
des informations relatives aux portes et télé-porteurs (après tout, y a pas des masses de différences entre les deux , et, enfin, le titre à afficher.
En respectant les conventions de ton propre code, la carte rouge pourrait ressembler à quelque choses comme
(en fait, ce qui suit les // n'apparait pas dans le fichier, je les ai juste rajoutés pour que tu comprennes de quoi il s'agit
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56 50 25 // 50 linges, 25 colonnes ######################## # # # # # ### # # #@####### # # # # # # # ! # # # # # ### # # # # # # # # # # ##### # # # # # # # # # ##### # # # # # ### ################# ## # # # # # # # # # ##### # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ################## ### # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ######################## 3 // 3 portes ou télé-porteurs 25 6 25 0 6 0 //la porte en 6,25 mène à la carte jaune (25,0) en position 6,0 2 5 45 31 50 50 // le télé-porteur en 2,5 mène à la carte bleue (45,31) en position 50,50 5 50 0 50 5 0 // la porte en 5,50 mène à la carte grise (0, 50) en position 5,0 desert
Et tu aurais un code pour charger ta map proche de
NOTA: tu devras peut etre prévoir quelque chose pour valider le format du fichier que tu lis, histoire de t'assurer que les données lues soient correctes, mais je ne vais quand meme pas tout faire pour toi
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 void loadMap(SMap & map, std::string const & filename) { map.tiles.clear(); //supprime les informations de la map précédante map.wraps.clear(); stdifstream ifs(filename); size_t rows; size_t cols; ifs>>rows>>cols; for(size_t y = 0; y <rows; ++y) { for(size_t x = 0; x <cols; ++x) { char c; ifs>>c; map.tiles.push_back(c); } } int wrapCount; ifs>>wrapCount; for(int i = 0; i< wrapCount;++i) { SWrap wrap; ifs>>wrap.sourceX>>wrap.sourceY >>wrap.destMapX>>wrap.destMapY >>wrap.destX>>wrap.destY; map.wraps.push_back(wrap); } ifs>>map.title; } // modifions la fonction main pour commencer dans la carte rouge int main() { std::map<Position, std::string> maplist; loadMapList(maplist) ; auto it= maplist.find(Position(0,0)); SMap map; loadMap(map, it.second); return 0; }
Bon, j’atteins de nouveau la taille d'un roman avec mon intervention, je vais donc m'arrêter là, histoire de te laisser le loisir de digérer tout cela
Hope it helps
A méditer: La solution la plus simple est toujours la moins compliquée
Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
Compiler Gcc sous windows avec MinGW
Coder efficacement en C++ : dans les bacs le 17 février 2014
mon tout nouveau blog
Euh, je ne sais pas pourquoi, je me croyais en C...
Quant aux zones de taille fixe, je raisonnais en termes de fichiers binaire et de localité mémoire totale (donc, pas de char*). Mais tu avais parfaitement raison sur le fait d'avoir besoin d'indiquer le nombre de téléporteurs.
@devdeb91: C'est à toi d'écrire le code pour interpréter les téléporteurs; personnellement, j'avais juste défini la structure.
Quand le joueur tombe sur un ':', le code doit parcourir la liste de warps de la map courante pour trouver le bon à partir de ses coordonnées (en gros, une bète recherche linéaire dans le tableau de 8). Puis, charger la map de destination si elle est différente, et déplacer le perso.
SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.
"Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
Apparently everyone. -- Raymond Chen.
Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.
@koala01 :
bon j'avoue que j'ai lâché en cours de route mais je vais relire et relire jusqu’à comprendre merci a toi
edit : alors voila quelques questions toutes bêtes
est on obliger de utiliser size_t peut on plutot ne pas utiliser int ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part size_t rows;
est on obliger de utiliser des unsigned et const car j'avoue ne jamais utiliser ceux la ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 const unsigned char tileAt(size_t x, size_t y) const {return tiles_[y*cols + x];}
en quoi consiste les instruction entre {} car je n'est jamais vue cette façon de coder ?
est il vraiment obliger des fonction comme map ou make_pair car j'avoue ne pas m'y connaitre au point de les connaitre a vrai dire c'est la première fois que je les vois
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 std::map<Position, std::string> maplist; toFill.insert(std::make_pair(Position(x,y),filename);
- Size_t est le type conseillé pour les tailles et indices de tableau.
- Pour le coup des unsigned char, je ne suis pas convaincu. Pour const, oui tu vas l'utiliser, tu vas le voir tous les jours et tu vas apprendre à l'aimer. La const-correctness est indispensable quand on bosse ainsi à bas niveau, sans filet.
- Par contre, un type de retour par valeur const, je ne vois pas trop à quoi ça sert.
- std::map est vachement utile. make_pair on peut peut-être s'en passer, je n'ai pas l'habitude de l'utiliser.
SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.
"Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
Apparently everyone. -- Raymond Chen.
Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.
Dans ce cas la pourriez vous m'expliquer a quoi sert std::map car j'ai beau lire sur internet cela ne m'apporte pas grande info
Source: http://en.cppreference.com/w/cpp/container/mapstd::map is a sorted associative container that contains key-value
pairs with unique keys.
Qu'est-ce que tu ne comprends pas dans cette phrase?
Un conteneur associatif associe une clee a une ou plusieurs valeur. Dans le cas de std::map, c'est une clee et une valeur.
make_pair() permet just de ne pas avoir a specifier les types des elements du constructeur de std::pair.Envoyé par Medinoc
deviens
Code : Sélectionner tout - Visualiser dans une fenêtre à part mon_index.insert( std::pair< int, std::string >( clee, valeur ) );
Ce qui est donc beaucoup plus facile a ecrire et lire dans du code generique, ou meme en general. Mais sinon ces deux codes sont equivalents (a ce que je sache).
Code : Sélectionner tout - Visualiser dans une fenêtre à part mon_index.insert( std::make_pair( clee, valeur ) );
dans ce cas laposition est la clé et étant une class
Code : Sélectionner tout - Visualiser dans une fenêtre à part std::map<Position, std::string> maplist;
il associe sa a une chaine si je comprend bien ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 class Position { public: Position(int x, int y):x_(x), y_(y){} int x() const{return x_;} int y() const{return y_;} private: int x_; int y_; };
Han s'te révélation *_*
A chaque fois que je vois un post partant de sémantique d'entité vs sémantique de valeur je me sens con car c'est un concept fondamental, mais il y a quelques semaines / mois, j'avais jamais entendu ces 2 termes.
Et la, en lisant ça, je me disais que j'aurais codé ça un peu différemment (sans vouloir relancer un énième débat sur les getters )
Bref je me rend compte qu'en fait même sans connaitre ces termes je faisait déjà la différence entre les 2, j'utilise des class pour les entités, des struct pour les valeurs.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 struct Position { const int x, y; Position(int x, int y): x(x), y(y) { } };
C'est une pratique courante ? (car j'ai forcément appris ça quelques part...)
Voila, ici la Position est la position d'une map dans "le monde" (Ou une grande map, regroupant toute les autres), et le string est le nom du fichier contenant la définition de cette map.
oh merci iradrille tu est mon sauveur voila ce que j'attendais. Là ça parait plus clair mais largement plus clair ça m'enlève déjà un blocage
edit: bon au point de paraitre lourd ( je vous l'accorde ) je vais quand même demander
ici aussi map est utilisé mais pas de la même syntaxe donc comment je dois interprété cette ligne (en langage humain)
Code : Sélectionner tout - Visualiser dans une fenêtre à part void loadMap(SMap & map, std::string const & filename)
D'abord, excusez cette réponse tardive, mais, étant nouvellement papa, je passe encore pas mal de temps à l'hopital C'est le problème des romans, ils contiennent un tas d'informations qu'il faut arriver à digérer
Mais n'hésite pas à demander des précision sur ce qui pose problème
edit : alors voila quelque question toute bete
En fait, size_t est un alias de type (un bête typedef en sommes ) sur un type non signé (donc dont la valeur minimal est 0) qui permet au minimum de représenter "n'importe quelle adresse accessible par le système".est on obliger de utiliser size_t peut on plutot ne pas utiliser int ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part size_t rows;
Comme il n'est vraiment pas conseillé d'utiliser un index négatif, le fait d'utiliser un entier non signé nous évite déjà ce genre de problème.
De plus, size_t est le type que renvoient certaines fonctions membres de pas mal de classes de la S(T)L, comme size() pour les différentes collections ou encore find_X_X_X pour la std::string.
Le fait d'utiliser directement le bon type pour chaque usage permet d'éviter:
Bref, cela t'évitera surement pas mal de soucis et de bugs "difficilement compréhensibles"
- un avertissement du compilateur (s'il est bien réglé) qui pourrait en fait dégénérer en
- un problème du à un dépassement de valeur (si tu utilises un type dont la fourchette de valeur est inférieure à celle à laquelle tu veux la comparer, par exemple)
j'aurais pu renvoyer un char non unsigned, non const...est on obliger de utiliser des unsigned et const car j'avoue ne jamais utiliser ceux la ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 const unsigned char tileAt(size_t x, size_t y) const {return tiles_[y*cols + x];}
Mais le const qui précède unsigned indique que le caractère renvoyé n'a pas vocation à être modifié.
Cela ne change pas grand chose ici, mais le fait est que, si tu prends l'habitude de déclarer constant tout ce qui n'a pas vocation à être modifié, tu fera du compilateur ton meilleur allié car il se mettra à t'insulter chaque fois que tu te mettras dans une situation où ce qui n'a pas à être modifié risque de l'être
Par contre, le const qui suit les parenthèses est particulièrement important parce qu'il indique au compilateur que cette fonction s'engage à ne pas modifier l'état de l'objet courent.
Tu peux sans problème appeler ce genre de fonctions sur des objets non constants (comprends: modifiables), mais tu ne peut appeler que des fonctions membres qui ont pris cet engagement depuis des objets constants (les deux coté d'une même pièce, en fait, qui font que le compilateur se transforme en ton meilleur allié )
Ben, c'est tout simple...en quoi consiste les instruction entre {} car je n'est jamais vue cette façon de coder ?
tiles est un objet de type std::vector qui n'est (faisons simple ) qu'une collection de type "tableau d'éléments contigus en mémoire".
Comme tous les tableaux d'élément contigus en mémoire, il est possible d'accéder à un élément donné sur base de son indice dans le tableau (sa "position" dans le tableau si tu préfères).
Le fait est que le tableau n'a ici qu'une dimension, alors que tu l'aurais sans doute représenté sous la forme d'un tableau à deux dimensions.
Il n'y a pas de problème quant au nombre d'éléments pour la simple et bonne raison qu'un tableau deux dimensions proche de
permet de représenter linges*colonnes éléments, et que cela reviens donc tout à fait au même que si l'on créait un tableau sous la forme de
Code : Sélectionner tout - Visualiser dans une fenêtre à part UnType tab2D[linges][colonnes];
qui contient lui aussi linges*colonnes éléments.
Code : Sélectionner tout - Visualiser dans une fenêtre à part UnType tab1D[linges*colonnes];
Seulement, voilà... tab2D (selon mon premier exemple) est en réalité un tableau de tableau, et c'est pour cela que l'on peut utiliser les deux opérateurs [] l'un à coté de l'autre alors que tab1D est... un tableau, sans plus, et on ne peut donc utiliser qu'un seul opérateur [].
Par chance, il existe une formule très simple pour convertir l'un en l'autre car si tu veut récupérer l'élément qui se trouve à la Yeme ligne et à la Xeme colonne (l'équivalent de tab2D[Y][X]), il te suffit d'accéder à l'élément qui se trouve à l'indice Y*(nombre de colonnes) + X dans tab1D.
Le code
ne fait rien d'autre qu'appliquer cette formule
Code : Sélectionner tout - Visualiser dans une fenêtre à part {return tiles_[y*cols + x];}
Mais peut etre es tu surtout étonné de voir l'implémentation de la fonction membre directement dans la définition de la classe
En fait, il faut savoir qu'il est totalement légal de le faire (sauf dans un cas particulier), et que je suis un peu flemmard par moment, mais que, en plus, cela a pour résultat de rendre implicitement la fonction inline (autrement dit: cela demande au compilateur de remplacer directement tous les appels à la fonction par le code de la fonction elle-même).
Cela peut améliorer grandement les performances pour des fonctions très simples, mais le compilateur reste seul juge pour décider de l'opportunité de le faire... ou non.
Dans le cas présent, la fonction est particulièrement simple (elle se traduit par une ou deux instruction(s) processeur(s) dans le code binaire exécutable) et on a donc la garantie qu'elle sera effectivement inlinée
Je gagne donc sur les deux tableaux en travaillant de la sorte: je gagne un peu de performances et je me laisse aller à ma flemmardise naturelle en évitant d'avoir à créer un fichier *.cpp "juste pour cela"
La fonction make_pair est juste une fonction que j'aime utiliser car elle permet de se faciliter la vie (autrement, tu dois toi-même créer une std :: pair avec les bons types et tout et tout... je trouve cela ch..ant, et moins lisible )est il vraiment obliger des fonction comme map ou make_pair car j'avoue ne pas m'i connaitre au point de les connaitre a vrai dire c'est la premiere fois que je l'est vois
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 std::map<Position, std::string> maplist; toFill.insert(std::make_pair(Position(x,y),filename);
en fait map est une classe fournie par le standard, et non une fonction...
C'est ce que l'on appelle un conteneur associatif qui associe une valeur (la std :: string) à une clé qui permet de retrouver très rapidement la valeur sur base de la clé.
C'est en fait un arbre binaire équilibré, qui permet une recherche dichotomique qui fait que tu n'a, par exemple, besoin que de 8 comparaisons pour retrouver un élément parmi 255 éléments potentiels
Tout à fait
Ca ne m'étonne absolument pas.
A part les cours de quelques pointures que l'on rencontre sur le forum, il y a très peu de cours (de langue francaise s'entend) où l'on en entende parler, pour être tout à fait honnête
Et pourtant, cette distinction est particulièrement importante, car elle te permet de déterminer très rapidement ce que tu peux envisager de demander à tes différentes classes... ou non
C'est une manière de faire qui n'est pas sans fondementEt la, en lisant ça, je me disais que j'aurais codé ça un peu différemment (sans vouloir relancer un énième débat sur les getters )
Bref je me rend compte qu'en fait même sans connaitre ces termes je faisait déjà la différence entre les 2, j'utilise des class pour les entités, des struct pour les valeurs.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 struct Position { const int x, y; Position(int x, int y): x(x), y(y) { } };Parles tu de ma pratique ou de la tienneC'est une pratique courante ? (car j'ai forcément appris ça quelques part...)
Sinon, je crois que c'est surtout une question d'habitude
Personnellement, j'ai pris l'habitude de limiter l'utilisation des structures à deux domaines:
- les structures vides (qui sont, généralement destinée à servir de flag )
- les foncteurs, dont je suis très friand
Et j'utilise les classes dés qu'il s'agit d'un type de donnée pour lesquels j’attends un certain nombre de services (fusse juste le fait de renvoyer la valeur d'un membre )
Je tiens à préciser qu'il s'agit ici d'une habitude strictement personnelle (quoi que me semble-t-il régulièrement rencontrée ), qui n'est ni plus ni moins justifiable que n'importe quelle habitude du même type.
Simplement, je trouve que cela permet d'avoir un code cohérent, dans lequel on invoque systématiquement une fonction au départ d'un objet pour en obtenir un service donné .
Il n'y a jamais de question idiote, il n'y a que les réponses qui le soient
Ceci dit, tu aurais peut etre pu trouver la réponse dans n'importe quel tutoriel correct
Mais bon, je suis décidément trop bon, et doncCette fonction ne renvoie rien et prend comme argumentsici aussi map est utilisé mais pas de la meme syntaxe donc comment je dois interprété cette ligne (en langage humain)
Code : Sélectionner tout - Visualiser dans une fenêtre à part void loadMap(SMap & map, std::string const & filename)
Alors, comme je présume que tu seras gras si je te laisse en plan avec cette explication, je vais être obligé d'aller un peu plus loin
- une référence (non constante) sur un objet de type SMap qui sera connu sous le nom de map
- une référence constante sur un objet de type std ::string qui sera connu sous le nom de filename
Mais, pour que l'explication ait un sens, il me faut commencer par rappeler un point essentiel:
Sauf indication contraire, les arguments sont passés aux fonctions par singleton, et le passage par valeur occasionne la copie de la variable transmise.
Le premier résultat est que si la fonction appelée modifie l'argument qu'elle reçoit par valeur, aucune des modifications qu'elle pourrait y apporter ne sera répercutée sur la variable qui a servi d'argument dans la fonction appelante.
De plus, la copie peut etre particulièrement gourmande en ressource (quant elle est autorisée), tant du point de vue du temps nécessaire à la copie que du point de vue de la mémoire utilisée.
Il fallait donc trouver le moyen d'éviter cette copie. En C, le seul moyen est de passer un pointeur. mais cela présente quelques désagréments (dont le moindre n'est pas le fait qu'un pointeur puisse être nul).
En C++, on peut disposer de références. Une référence n'est jamais qu'un "alias" de l'objet auquel elle fait ... (référence ).
L'énorme avantage (en dehors de la syntaxe pour la manipuler) de la référence est qu'elle référence d'office un objet qui existe (elle offre une garantie de non nullité )
De plus, comme il s'agit d'un alias, toutes les modifications qui y seront apportées au niveau de la fonction appelée seront automatiquement répercutées dans la fonction appelante (tout comme tout ce qui arrive à devdeb91 t'arrive en réalité à toi ).
Le deuxième avantage que les références ont sur les pointeurs, c'est qu'elle respectent la constante: si tu informes le compilateur que la référence n'a absolument pas vocation à être modifiée, il est en mesure de s'assurer que tu ne fais rien qui tente de la modifier, et de t'insulter dans le cas contraire.
C'est la raison pour laquelle je passe la SMap sous la forme d'une référence car le but de la fonction est... de charger (donc de modifier) l'argument connu sous le nom de map, mais que je passe filename sous la forme d'une référence constante , parce qu'il n'y a strictement aucune raison que la fonction essayes de modifier le nom que je lui donne
A méditer: La solution la plus simple est toujours la moins compliquée
Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
Compiler Gcc sous windows avec MinGW
Coder efficacement en C++ : dans les bacs le 17 février 2014
mon tout nouveau blog
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager