Bonjour a tous,

J'essaie depuis quelques temps d'afficher des cartes aléatoires en isométrique. Pour ce qui est de la génération de la carte je n'ai pas de problème, mais la ou je bloque, c'est lorsqu'il me faut choisir la bonne image de tile a afficher selon les autres tiles qui l'entour.

En gros, j'essaie de faire quelque chose qui ressemble a une carte de simcity2000. Voir image:

Nom : images.jpg
Affichages : 918
Taille : 12,2 Ko

Vous voyer les reliefs des montagnes sur l'image, et bien je cherche a faire parreil.

Comme je disais, générer la carte dans un tableau ça va, afficher des tiles en iso ça va aussi, mon problème c'est vraiment de faire un algorithme qui va décider si je dois mettre le dessin 0 ou le 1 ou le 2... qui correspondent a une tile plate, ou bien un angle au nord, ou au sud, ou bien un coin...

voici mon code (test) que je trafique dans tout les senses depuis longtemps (désolé, c'est un peu le bordel, je suis un amateur et le code est pas optimisé):

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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
 
#! /usr/bin/env python
# -*- coding: utf-8 -*-
 
#Importation des modules
try:
    import os, pygame, random
except ImportError as err:
    print("Impossible de charger le module: ", err)
    print("Sortie forcé du systeme")
 
#Constante de la fenêtre
PLACE = "center" #emplacement de la fenetre dans l'écran
TITLE = "TestIso"
 
#Constantes du jeu
FPS = 90 #nombre d'image par seconde
SCROLLING = 5 #vitesse du scrolling
TILESIZE = (112,83,27)
 
#Fonction
def loadImage(name, color=None):
    """Charge les images et retourne un object image, si color = -1
    la fonction prend le pixel à l'adresse (0,0) comme référence à
    la couleur de transparence. L'image doit être dans le dossier
    "images" """
    cheminImage = os.path.join("images", name)
    try:
        image = pygame.image.load(cheminImage).convert_alpha()
 
        if color == -1:
            color = image.get_at((0,0))
 
        if color != None:
            image.set_colorkey(color)
 
        return image
 
    except pygame.error:
        print ("Impossible de charger l'image:", name)
 
        return None
 
def decoupe(image, size):
    """Découpe un tile-set en bloque selon la taille (en pixels) des tuiles
    et retourne toutes les images dans une liste"""
    lImage = []
    for b in range(0, image.get_height(), size[1]):
        for a in range(0, image.get_width(), size[0]):
            lImage.append(image.subsurface(a, b, size[0], size[1]))
 
    return lImage
 
def builtMap(size, relief, erosion):
    """Générateur de carte"""
 
    #Crée une carte plate de niveau 0
    liste = []
    for y in range(size[1]):
        l1 = []
        for x in range(size[0]):
            l1.append(0)
        liste.append(l1)
 
    #Déplace un curseur de niveau 255 dans la map aléatoirement en prennent
    #en compte les collision avec les bords de la map ce qui crée un relief
 
    #position et direction de départ aléatoire
    x,y = random.randrange(0, int(size[0])), random.randrange(0, int(size[1]))
    direction = random.choice([(-1,0),(1,0),(0,-1),(0,1),(-1,1),(1,1),(1,-1)])
 
    for i in range(relief):
 
        #change la couleur de la case   
        liste[y][x] = 100
 
        x += direction[0]
        y += direction[1]
 
        #change de direction en cas de sortie des limites
        dx, dy = direction
        if x < 0 or x > len(liste[0])-1:
            x -= direction[0]
            dx = -dx
        if y < 0 or y > len(liste)-1:
            y -= direction[1]
            dy = -dy
        direction = (dx,dy)
 
        #change la direction en cour de route (1 chance sur 10)
        choix = random.randrange(0,10)
        if choix == 0:
            direction = random.choice([(-1,0),(1,0),(0,-1),(0,1),(-1,1),(1,1),(1,-1)])
 
 
    #Crée un contour de niveau 0 sur la carte pour donné une effet
    #d'ile
    a = 0
    for ligne in liste:
        b = 0
        for data in ligne:
            if a <= 5:
                liste[a][b] = 0
            elif a >= len(liste)-6:
                liste[a][b] = 0
            elif b <= 5:
                liste[a][b] = 0
            elif b >= len(liste[0])-6:
                liste[a][b] = 0
 
            b += 1
        a += 1
 
 
    #Affine la carte en lissant les arrêtes des niveaux de la map, prend chaque
    #case autour de la case concerné et fais une moyenne des niveaux que l'on attribue
    #ensuite à la case concerné
    for i in range(erosion):
        y = 0
        for ligne in liste:
            x = 0
            for value in ligne:
                try:
                    #Vérifie si la case est l'une des quatres coin ou non, puis calcul
                    #la moyenne des niveaux des cases autour de la case, le bloc try
                    #est pour éviter un dépassement de liste
                    if x == 0 and y == 0:
                        newValue = int((liste[y][x+1]+liste[y+1][x]+liste[y+1][x+1])/3)
                    elif x == len(liste[0])-1 and y == len(liste)-1:
                        newValue = int((liste[y-1][x-1]+liste[y-1][x]+liste[y][x-1])/3)
                    elif x == len(liste[0])-1 and y == 0:
                        newValue = int((liste[y][x-1]+liste[y+1][x-1]+liste[y+1][x])/3)
                    elif x == 0 and y == len(liste[0])-1:
                        newValue = int((liste[y-1][x]+liste[y-1][x+1]+liste[y][x+1])/3)
                    elif x == len(liste[0])-1:
                        newValue = int((liste[y-1][x-1]+liste[y-1][x]+liste[y][x-1]+\
                                        liste[y+1][x-1]+liste[y+1][x])/5)
                    elif y == len(liste)-1:
                        newValue = int((liste[y-1][x-1]+liste[y-1][x]+liste[y-1][x+1]+\
                                        liste[y][x-1]+liste[y][x+1])/5)
                    else:
                        newValue = int((liste[y-1][x-1]+liste[y-1][x]+liste[y-1][x+1]+\
                                        liste[y][x-1]+liste[y][x+1]+liste[y+1][x-1]+\
                                        liste[y+1][x]+liste[y+1][x+1])/8)
                except:
                    pass
 
                #donne la valeur calculé à la case
                liste[y][x] = newValue
                x += 1
            y += 1
 
    return liste
 
def formatHeight(liste, nbLevel, height):
 
    liste2 = []
    for ligne in liste:
        l = []
        for data in ligne:
 
            data = int(data/nbLevel)
            data *= height
 
            l.append(data)
 
        liste2.append(l)
 
    return liste2
 
def formatMap(liste):
 
    liste2 = []
    j = 0
    for ligne in liste:
        l = []
        i = 0
        for data in ligne:
 
            data2 = None
 
            try:
                if liste[j][i-1] > data:
                    data2 = 2
            except:
                pass
 
            try:
                if liste[j-1][i] > data:
                    data2 = 1
            except:
                pass
 
            try:
                if liste[j][i+1] > data:
                    data2 = 4
            except:
                pass
 
            try:
                if liste[j+1][i] > data:
                    data2 = 3
 
            except:
                pass
 
            try:
                if liste[j-1][i-1] > data and liste[j-1][i] == data and liste[j][i-1] == data:
                    data2 = 5
            except:
                pass
 
            try:
                if liste[j+1][i-1] > data and liste[j+1][i] == data and liste[j][i-1] == data:
                    data2 = 6
            except:
                pass
 
            try:
                if liste[j+1][i+1] > data and liste[j+1][i] == data and liste[j][i+1] == data:
                    data2 = 7
            except:
                pass
 
            try:
                if liste[j-1][i+1] > data and liste[j-1][i] == data and liste[j][i+1] == data:
                    data2 = 8
            except:
                pass
 
            if data2 == None:
                data2 = 0
 
            l.append(data2)
            i += 1
 
        liste2.append(l)
        j += 1
 
    for j in range(0,len(liste2)):
        for i in range(0,len(liste2[0])):
 
            try:
                if liste2[j+1][i] == 5 and liste2[j][i+1] == 5:
                    liste2[j][i] = 9
            except:
                pass
 
##            try:
##                if liste2[j-1][i] == 6 and liste2[j][i+1] == 6:
##                    liste2[j][i] = 10
##            except:
##                pass
 
            try:
                if liste2[j-1][i] == 7 and liste2[j][i-1] == 7:
                    liste2[j][i] = 11
            except:
                pass
 
    return liste2
 
#Classes        
class Game():
    """Gère tout les éléments du jeu"""
 
    def __init__(self, **kwarg):
        """Constructeur:
        parametre =
        title (str) = Titre de la fenêtre
        screenSize (width, height) = Taille de l'écran
        fullscreen (bool) = Option de plein écran
        sound (bool) = Option du son"""
 
        title = "Game"
        screenSize = (800,600)
        fullScreen = False
 
        for key in kwarg:
            if key == "title": title = kwarg[key]
            elif key == "screenSize": screenSize = kwarg[key]
            elif key == "fullScreen": fullScreen = kwarg[key]
            else: raise ValueError("Invalid Argument :"+key)
 
        pygame.init()
        os.environ['SDL_VIDEO_CENTERED'] = PLACE
 
        if fullScreen:
            self.screen = pygame.display.set_mode(screenSize, pygame.FULLSCREEN)
        else:
            self.screen = pygame.display.set_mode(screenSize)
 
        pygame.mouse.set_visible(True)
        pygame.key.set_repeat(100,30)
        pygame.display.set_caption(title)
 
        self.area = self.screen.get_rect()
        self.run = True
 
        self.loadImage()
        self.createObjet()
        self.loop()
 
 
    def loadImage(self):
 
        mask = loadImage("tileMask.png")
        self.listMask = decoupe(mask, (TILESIZE[0],TILESIZE[1]))
 
    def createObjet(self):
        """Crée tous les objets et/ou les prépares"""
 
        self.pause = False
 
        heightMap = builtMap((50,50), 1000, 5) #carte en niveau de gris
        heightTile = formatHeight(heightMap, 10, TILESIZE[2]) #hauteur des tiles
        numberTile = formatMap(heightTile)
        self.map = Layout(numberTile, heightTile, self.listMask)
 
    def loop(self):
        """Boucle principal"""
        while self.run:
 
            pygame.time.Clock().tick(FPS)
 
            self.event()
            self.scrolling()
 
            if not self.pause:
                None
 
            self.render()
 
        pygame.quit()
 
    def event(self):
        """Gère tout les évènements concenant la fenêtre (clavier/sourie)"""
        #Gestion clavier
        for ev in pygame.event.get():
 
            if ev.type == pygame.QUIT:
                self.run = False
 
            #Sortie de programme                    
            if ev.type == pygame.KEYDOWN:
                if ev.key == pygame.K_ESCAPE:
                    self.run = False
 
                #reset tout les objets (les recrées)
                elif ev.key == pygame.K_r:
                    self.createObjet()
 
                #Set/reset pause
                elif ev.key == pygame.K_p:
                    if self.pause:
                        self.pause = False
                    else:
                        self.pause = True
 
    def scrolling(self):
 
        self.map.scrolling()
 
    def render(self):
        """Gère l'affichage de tout les objets"""
 
        #background
        self.screen.fill((0,0,0))
 
        #affiche la carte
        self.map.display()
 
        #actualize
        pygame.display.flip()
 
class Layout():
    """Crée une carte (liste de liste) d'objet Tile, selon un plan
       et dimentionne le tout selon la taille des tile (TILESIZE)
       et leur couleur (COLORWALL, COLORGROUND, COLORSTART et COLOREND)"""
 
    def __init__(self, plan, heightTile, listMask):
        """Constructeur"""
        self.screen = pygame.display.get_surface()
        self.area = self.screen.get_rect()
 
        self.listMask = listMask
 
        self.map = []
        y = 0
        for ligne in plan:
            x = 0
            for data in ligne:
 
                self.map.append(Tile((x,y), listMask[data], heightTile[y][x]))
 
                x += 1
            y += 1
 
    def scrolling(self):
 
        if pygame.key.get_pressed()[pygame.K_UP]:
            for element in self.map:
                element.move((0,SCROLLING))
        if pygame.key.get_pressed()[pygame.K_DOWN]:
            for element in self.map:
                element.move((0,-SCROLLING))
        if pygame.key.get_pressed()[pygame.K_LEFT]:
            for element in self.map:
                element.move((SCROLLING,0))
        if pygame.key.get_pressed()[pygame.K_RIGHT]:
            for element in self.map:
                element.move((-SCROLLING,0))
 
    def get_map(self):
 
        return self.map
 
    def display(self):
        """Affiche tout les elements de la carte"""
        for element in self.map:
            element.display()
 
class Tile():
    """Crée une tuile carré"""
 
    def __init__(self, adresse, image, height):
        """Constructeur"""
 
        self.screen = pygame.display.get_surface()
        self.area = self.screen.get_rect()
 
        self.image = image
        self.rect = self.image.get_rect()
 
        self.height = height
        self.adresse = adresse
 
        x = adresse[0]*int(self.rect.width/2)-adresse[1]*(self.rect.height-TILESIZE[2])
        y = adresse[0]*int((self.rect.height-TILESIZE[2])/2)+adresse[1]*int((self.rect.height-TILESIZE[2])/2)
        self.rect.topleft = (x,y-self.height)
 
    def move(self, coord):
 
        self.rect = self.rect.move(coord)
 
    def display(self):
 
        if self.area.colliderect(self.rect):
            self.screen.blit(self.image, self.rect)
 
#Execution
if __name__ == "__main__":
 
    Game(title=TITLE, fullScreen=False)
et les images:

Nom : tileMask.png
Affichages : 1558
Taille : 5,1 Ko

En gros ce que le code fait, on génère un carte aléatoire (une ile) dans builtmap, ce qui me donne une liste de hauteur de 0 a 100, ensuite je format ces hauteurs (dans une nouvelle liste) selon la hauteur des tiles pour créé des niveaux (des plateaux de montagne), ensuite a partir de cette nouvelle liste je choisi les bonne images a afficher, ensuite et bien c'est comme pour toutes carte en iso, je crée des objets tiles avec l'image et la hauteur de la tiles dans une liste et ensuite j'affiche chaque élément de la liste.

Comme je disais, je suis très très amateur, donc c'est peu-être juste ma façons de faire qui n'est pas bonne, dans tout les cas, je suis ouvert au critique.

Merci pour votre aide,

Pascal