Partage
  • Partager sur Facebook
  • Partager sur Twitter

problème de classe pour un jeu Pygame

    19 mai 2014 à 18:31:48

    Bonjour, je travaille sur un jeu depuis quelques mois. J'essaye de créer un jeu du style RPG, et je me suis beaucoup inspiré du TP-DKLaby du tutoriel pygame. J'ai ainsi défini mes classes, fonction, et événements. J'ai réussi à créer un premier niveau, mais lorsque j'ai voulu en créer un deuxième je me suis heurté a un gros problème. Après avoir atteint le bout de la map et activé la fonction de changement de niveau, le nouveau niveau se crée, puis est immédiatement remplacé par le premier . Je ne comprend pas ce problème, je pense qu'il doit venir de la classe du personnage ou alors des fonctions. En effet, je sais que le niveau est chargé avec les bonnes matrices, mais c'est comme si les fonctions ne prenaient pas en compte le changement de matrice.

    voici mon code,

    # ---------- imports ----------
    from random import *
    import pygame
    from pygame.locals import *
    from math import *
    from test_save import *
    from niveau import *
    from time import sleep
    import time
    # ---------- Programme Principal ----------
    
    #---------------initialisation et création des variables-----------
    
    pygame.init()
    fenetre = pygame.display.set_mode((640, 480))
    taillesprite = 32
    epee = objet() 
    coup = shoot()
    fantom1 = pnj()
    LV1 = "labyTRUE.txt"
    LV1_1 = "testevent2TRUE.txt"
    LV2 = "map2TRUE.txt"
    LV2_1 = "map22TRUE.txt"
    niveau = Niveau(LV1)
    niveau.generer()
    sous_niveau = Niveau(LV1_1)
    sous_niveau.generer()
    shootdk = shoot()
    dk = Perso(niveau, sous_niveau)
    font = pygame.font.Font(None, 36)
    text = font.render("Va chercher banane !!", 1,(10,10,10))
    vie = pygame.image.load("coeur.png").convert_alpha()
    font1 = pygame.font.Font(None, 36)
    nb = dk.vita
    nombre = font1.render('%d' %nb, 1,(15,1,10))
    pygame.display.flip()
    pygame.key.set_repeat(400, 30)
    continuer = 0
    continuer_acceuil = 1
    pygame.mixer.init()
    son = pygame.mixer.Sound("thelook8bit4.wav")
    save = ('save.txt')
    playing = True
    
    
    #------------------boucle principale-------------------
    
    while True :
        pygame.init()
        fenetre = pygame.display.set_mode((640, 480))
    	
    	
    	
        while continuer == 0 :
    	print("je suis dans la boucle 0")		
    	pygame.init()
    	pygame.display.init()
    	start = pygame.image.load("manoir.png").convert_alpha()
            fenetre.blit(start, (0,0))
            pygame.display.flip()
            for event in pygame.event.get():
                        if event.type==QUIT:
                            pygame.quit()
    			print(niveau.structure)
    			print(sous_niveau.structure)			
                        if event.type == KEYDOWN :
                            if event.key == K_UP :
    			    start = pygame.image.load("transparent.png").convert_alpha()
    			    ouverture (event, dk, save)
    			    continuer = 1
    			if event.key == K_DOWN :
    			    pygame.quit()
    			    
        while continuer == 1 :
    	print("je suis dans la boucle 1")	
    	pygame.init()
    	pygame.display.init()
    	start = pygame.image.load("transparent.png").convert_alpha()
    	pygame.display.flip
    	son.play()#joue le son
    	sous_niveau = Niveau(LV1_1)
    	sous_niveau.generer()	
    	niveau = Niveau (LV1) #génération du LVL
    	niveau.generer ()
    	niveau.afficher(fenetre)
    	nb = dk.vita
    	distanceA = sqrt((dk.dkx - epee.x)*(dk.dkx - epee.x) + (dk.dky - epee.y)*(dk.dky - epee.y)) # variables de distance
    	distanceB = sqrt((dk.dkx - fantom1.x)*(dk.dkx - fantom1.x) + (dk.dky - fantom1.y)*(dk.dky - fantom1.y))
    
    
    	for event in pygame.event.get():
    			if event.type == QUIT :
    				pygame.quit()
    				print(niveau.structure)
    				print(sous_niveau.structure)				
    			
    			deplacement(event, dk, shootdk, nb)
    			event1(dk, distanceA,nb)
    			eventpnj (distanceB, dk,nb)
    			vie_supp (dk,nb)
    			changement(dk,nb)
    			brise_mur(dk,nb, LV1, LV1_1)
    			if event.type == KEYDOWN :
    				if event.key == K_s :
    					sauvegarde (event, dk, save)			
    			if dk.vita == 0 :
    			    continuer = 2
    			if dk.changement == 1 :
    			    changement(dk,nb)			    
    			    continuer = 3			
        
        while continuer == 2 :
    	print("je suis dans la boucle 2")
    	pygame.init()
    	pygame.display.init()
    	game_over = pygame.image.load("gameover.png").convert_alpha()
    	fenetre.blit(game_over, (0,0))
    	pygame.display.flip()
    	for event in pygame.event.get():
    	    if event.type==QUIT:
    		pygame.quit() 
    		print(niveau.structure)
    		print(sous_niveau.structure)		
    	    if event.type == KEYDOWN :
    		if event.key == K_UP :
    		    continuer = 0
    		if event.key == K_DOWN :
    		    pygame.quit()
        
        while continuer == 3 :
    	print("je suis dans la boucle 3")
    	pygame.init()
    	pygame.display.init()
    	start = pygame.image.load("transparent.png").convert_alpha()
    	pygame.display.flip
    	son.play()#joue le son
    	sous_niveau = Niveau(LV2_1)
    	sous_niveau.generer()
    	niveau = Niveau(LV2)
    	niveau.generer()
    	niveau.afficher (fenetre)
    	#dk = Perso(niveau, sous_niveau)	
    	nb = dk.vita
    	distanceA = sqrt((dk.dkx - epee.x)*(dk.dkx - epee.x) + (dk.dky - epee.y)*(dk.dky - epee.y)) # variables de distance
    	distanceB = sqrt((dk.dkx - fantom1.x)*(dk.dkx - fantom1.x) + (dk.dky - fantom1.y)*(dk.dky - fantom1.y))
    
    
    	for event in pygame.event.get():
    			if event.type == QUIT :
    				pygame.quit()
    				print(niveau.structure)
    				print(sous_niveau.structure)				
    			
    			deplacement(event, dk, shootdk, nb)
    			event1(dk, distanceA,nb)
    			eventpnj (distanceB, dk,nb)
    			vie_supp (dk,nb)
    			#changement(dk,nb)
    			if event.type == KEYDOWN :
    				if event.key == K_s :
    					sauvegarde (event, dk, save)			
    			if dk.vita == 0 :
    				continuer = 2		
    
    	
    	
    	
    	
                            
        
    	
    							
    
    
    		
    pygame.quit()
    

    Le code de mes classes et fonctions :

    # ---------- imports ----------
    from random import *
    import pygame
    from pygame.locals import *
    from math import *
    from niveau import *
    from time import sleep
    import time
    import shelve 
    # ---------- Programme Principal ----------
    pygame.init()
    fenetre = pygame.display.set_mode((640, 480))
    LV1 = "labyTRUE.txt"
    LV1_1 = "testevent2TRUE.txt"
    LV2 = "map2TRUE.txt"
    LV2_1 = "map22TRUE.txt"
    sous_niveau = Niveau(LV1_1)
    sous_niveau.generer()
    niveau = Niveau(LV1)
    niveau.generer()
    niveau.afficher (fenetre)
    
    
    
    #-----------------Creation des classes objet/perso
    class Perso :
    	"""
    	création du personnage avec toutes ses caractéristiques
    	"""
    	def __init__(self, niveau = niveau, sous_niveau = sous_niveau ):
    		self.dk_face = pygame.image.load("perso_droite.png").convert_alpha()
    		self.dk_bas = pygame.image.load("perso_face.png").convert_alpha()
    		self.dk_gauche = pygame.image.load("perso_gauche.png").convert_alpha()
    		self.dk_haut = pygame.image.load("perso_haut.png").convert_alpha()
    		self.dkx = 64
    		self.dky = 470
    		self.case_x = 2
    		self.case_y = 14		
    		self.vitesse = 1
    		self.direction = self.dk_face
    		self.niveau = niveau
    		self.sous_niveau = sous_niveau
    		self.epee = 0
    		self.vita = 3 
    		self.changement = 0
    	def mouvement (self, direction) :
    		#création de la fonction de déplacement
    		if direction == 'droite' :
    			if self.dkx + (self.vitesse*32) < 640: 
    				#verifie que le perso ne dépassera pas l'écran (en fonction de sa vitesse)
    				if self.niveau.structure[self.case_y][self.case_x+self.vitesse] != "1":
    					if self.sous_niveau.structure[self.case_y][self.case_x+self.vitesse] != "1" and self.sous_niveau.structure[self.case_y][self.case_x+self.vitesse]!= "2" :
                                            #verifie que la case d'arrivée ne soit pas un mur ni un pnj( en fonction de la vitesse)
    							self.case_x += self.vitesse
    							self.dkx += (self.vitesse*32)
    							self.direction = self.dk_face
    		elif direction == 'gauche' :
    			if self.dkx - (self.vitesse*32) > 0:
    				if self.niveau.structure[self.case_y][self.case_x-self.vitesse] != "1":
    					if self.sous_niveau.structure[self.case_y][self.case_x-self.vitesse] != "1" and self.sous_niveau.structure[self.case_y][self.case_x-self.vitesse] != "2" :
    							self.case_x += -self.vitesse
    							self.dkx += -(self.vitesse*32)
    							self.direction = self.dk_gauche
    		elif direction == 'haut' :
    			if self.dky - (self.vitesse*32) > 0 :
    				if self.niveau.structure[self.case_y-self.vitesse][self.case_x] != "1":
    					if self.sous_niveau.structure[self.case_y-self.vitesse][self.case_x] != "1" and self.sous_niveau.structure[self.case_y-self.vitesse][self.case_x] != "2":
    							self.case_y += -self.vitesse
    							self.dky += -(self.vitesse*32)
    							self.direction = self.dk_haut
    		elif direction == 'bas' :
    			if self.dky + (self.vitesse*32) < 480 :
    				if self.niveau.structure[self.case_y+self.vitesse][self.case_x] != "1":
    					if self.sous_niveau.structure[self.case_y+self.vitesse][self.case_x] != "1"and self.sous_niveau.structure[self.case_y+self.vitesse][self.case_x] != "2":
    							self.case_y += self.vitesse
    							self.dky += (self.vitesse*32)
    							self.direction = self.dk_bas
    		elif direction == 'retourd' :
    			self.case_x += -self.vitesse
    			self.dkx += -(self.vitesse*32)
    			self.direction = self.dk_face
    			self.vita += -1
    		elif direction == 'retourg' :
    			self.case_x += self.vitesse
    			self.dkx += (self.vitesse*32)
    			self.direction = self.dk_gauche
    			self.vita += -1
    		elif direction == 'retourh' :
    			self.case_y += self.vitesse
    			self.dky += (self.vitesse*32)
    			self.direction = self.dk_haut
    			self.vita += -1
    		elif direction == 'retourb' :
    			self.case_y += -self.vitesse
    			self.dky += -(self.vitesse*32)
    			self.direction = self.dk_bas
    			self.vita += -1
    		elif direction == 'start' :
    			self.case_x = 1
    			self.case_y = 10
    			self.dkx = 32
    			self.dky = 320
     
            
    
    
    class objet :
    	#classe de l'objet qui sert de base pour les événement
    	def __init__(self) :
    		self.objet = pygame.image.load("sword.png").convert_alpha()
    		self.x = 160
    		self.y = 160
    		self.case_x = 5
    		self.case_y = 5
    		self.niveau = niveau
    
                
    class shoot :
    	#classe de l'objet qui servira de tir
    	def __init__(self):
    		self.shoot = pygame.image.load("sword.png").convert_alpha()
    		self.case_x = 0
    		self.case_y = 0
    		self.x = 0
    		self.y = 0
    		self.niveau = niveau
    		self.sous_niveau = sous_niveau
    	
    
    	
    		
    
    
    class pnj :
    	def __init__(self):			
    		self.fantom_face = pygame.image.load("pnj1.png").convert_alpha()
    		self.x = 128
    		self.y = 320
    		self.case_x = 4
    		self.case_y = 10
    		self.niveau = niveau
    			
    
    #--------------Creation de variables pour definir les fonctions----------------
    		
    		
    
    dk = Perso(niveau, sous_niveau)
    epee = objet()
    shootdk = shoot()
    fantom1 = pnj()
    font = pygame.font.Font(None, 36)
    text = font.render("Va chercher epee !!", 1,(10,10,10))
    message = 'va chercher la epee!!'
    vie = pygame.image.load("coeur.png").convert_alpha()
    font1 = pygame.font.Font(None, 36)
    nb = dk.vita
    nombre = font1.render('%d' %nb, 1,(10,10,10))
    distanceA = sqrt((dk.dkx - epee.x)*(dk.dkx - epee.x) + (dk.dky - epee.y)*(dk.dky - epee.y))
    distanceB = sqrt((dk.dkx - fantom1.x)*(dk.dkx - fantom1.x) + (dk.dky - fantom1.y)*(dk.dky - fantom1.y))
    save = ('save.txt')
    continuer = 0
    
    #---------------Creation des fonctions/événements----------------
    
    
    def sauvegarde (event, dk, fichier) :
    	f = open("historique", 'w')
    	L0 = dk.vita
    	L1 = dk.dkx
    	L2 = dk.dky
    	L3 = dk.case_x
    	L4 = dk.case_y
    	L5 = dk.epee
    	L6 = dk.vitesse
    
    	# sauvegardes des objets
    	f.write(repr(L0)+'\r\n')
    	f.write(repr(L1)+'\r\n')
    	f.write(repr(L2)+'\r\n')
    	f.write(repr(L3)+'\r\n')
    	f.write(repr(L4)+'\r\n')
    	f.write(repr(L5)+'\r\n')
    	f.write(repr(L6)+'\r\n')
    
    	f.close()
    
    def ouverture (event, dk, fichier) :
    	f = open("historique", 'r')
    	 
    	# récupération des objets sauvegardés
    	dk.vita = eval(f.readline().rstrip('\r\n'))
    	dk.dkx = eval(f.readline().rstrip('\r\n'))
    	dk.dky = eval(f.readline().rstrip('\r\n'))
    	dk.case_x = eval(f.readline().rstrip('\r\n'))
    	dk.case_y = eval(f.readline().rstrip('\r\n'))
    	dk.epee = eval(f.readline().rstrip('\r\n'))
    	dk.vitesse = eval(f.readline().rstrip('\r\n'))
    	f.close()
    	
    
    
    def deplacement (event, dk, shootdk, nb1) :
    	"""
    	définition d'une fonction qui recupere toute les focntionalité du perso, sera appelé dans la boucle principale
    	"""
    	if event.type == KEYDOWN :
    		#Touches de déplacement de Donkey Kong
    		if event.key == K_RIGHT:
    			#droite
    			dk.mouvement('droite')
    						
    			
    		if event.key == K_LEFT:
    			#gauche
    			dk.mouvement('gauche')
    						
    
    		if event.key == K_UP:
    			#haut
    			dk.mouvement('haut')
    						
    
    		if event.key == K_DOWN:
    			#bas
    			dk.mouvement('bas')
    						
    			
    		if dk.niveau.structure[dk.case_y][dk.case_x] == "7" and dk.direction == dk.dk_face :
    			dk.mouvement('retourd') #retour en arriere en cas de troue
    			nb1 += -1
    			nombre = font1.render('%d' %nb1, 1,(10,10,10))
    			fenetre.blit(epee.objet, (epee.x, epee.y))	
    			fenetre.blit(dk.direction, (dk.dkx, dk.dky)) #dk.direction = l'image dans la bonne direction
    			fenetre.blit(fantom1.fantom_face, (fantom1.x, fantom1.y))
    			fenetre.blit(vie, (0,0))
    			fenetre.blit(nombre, (32,32))			
    			pygame.display.flip()				
    			print(dk.vita)
    		if dk.niveau.structure[dk.case_y][dk.case_x] == "7" and dk.direction == dk.dk_bas :
                                    dk.mouvement('retourb')
    				nb1 += -1
    				nombre = font1.render('%d' %nb1, 1,(10,10,10))
    				fenetre.blit(epee.objet, (epee.x, epee.y))	
    				fenetre.blit(dk.direction, (dk.dkx, dk.dky)) #dk.direction = l'image dans la bonne direction
    				fenetre.blit(fantom1.fantom_face, (fantom1.x, fantom1.y))
    				fenetre.blit(vie, (0,0))
    				fenetre.blit(nombre, (32,32))				             
    				pygame.display.flip()				
    				print(dk.vita)
    		if dk.niveau.structure[dk.case_y][dk.case_x] == "7"  and dk.direction == dk.dk_haut:
                                    dk.mouvement('retourh')
    				nb1 += -1
    				nombre = font1.render('%d' %nb1, 1,(10,10,10))
    				fenetre.blit(epee.objet, (epee.x, epee.y))	
    				fenetre.blit(dk.direction, (dk.dkx, dk.dky)) #dk.direction = l'image dans la bonne direction
    				fenetre.blit(fantom1.fantom_face, (fantom1.x, fantom1.y))
    				fenetre.blit(vie, (0,0))
    				fenetre.blit(nombre, (32,32))				
    				pygame.display.flip()				
    				print(dk.vita)
    		if dk.niveau.structure[dk.case_y][dk.case_x] == "7" and dk.direction == dk.dk_gauche :
                                    dk.mouvement('retourg')
    				nb1 += -1
    				nombre = font1.render('%d' %nb1, 1,(10,10,10))
    				fenetre.blit(epee.objet, (epee.x, epee.y))	
    				fenetre.blit(dk.direction, (dk.dkx, dk.dky)) #dk.direction = l'image dans la bonne direction
    				fenetre.blit(fantom1.fantom_face, (fantom1.x, fantom1.y))
    				fenetre.blit(vie, (0,0))
    				fenetre.blit(nombre, (32,32))				
    				pygame.display.flip()				
    				print(dk.vita)		
    
    
    		if event.key == K_e  and dk.epee == 1 :
    			#fonction du coup d'épée en fonction de la direction
    			if dk.direction == dk.dk_face :
    				shootdk.x = (dk.dkx +20)
    				shootdk.y = dk.dky
    				shootdk.case_x = (dk.case_x + 1)
    				shootdk.case_y = dk.case_y
    				shootdk.shoot = pygame.image.load("swordd.png").convert_alpha()				
    			if dk.direction == dk.dk_bas :				
    				shootdk.x = dk.dkx
    				shootdk.y = (dk.dky +20)
    				shootdk.case_x = dk.case_x
    				shootdk.case_y = (dk.case_y +1)				
    				shootdk.case_x = dk.case_x
    				shootdk.case_y = (dk.case_y +1)	
    				shootdk.shoot = pygame.image.load("swordb.png").convert_alpha()				
    			if dk.direction == dk.dk_haut :				
    				shootdk.x = dk.dkx
    				shootdk.y = (dk.dky -20)
    				shootdk.case_x = dk.case_x 
    				shootdk.case_y = (dk.case_y -20)			
    				shootdk.shoot = pygame.image.load("swordh.png").convert_alpha()				
    			if dk.direction == dk.dk_gauche :
    				shootdk.x = (dk.dkx -20)
    				shootdk.y = dk.dky
    				shootdk.case_x = (dk.case_x -1 )
    				shootdk.case_y = dk.case_y
    				shootdk.shoot = pygame.image.load("swordg.png").convert_alpha()
    				
    				
    			nombre = font1.render('%d' %nb1, 1,(10,10,10))	
    			fenetre.blit(epee.objet, (epee.x, epee.y))	
    			fenetre.blit(dk.direction, (dk.dkx, dk.dky)) #dk.direction = l'image dans la bonne direction
    			fenetre.blit(shootdk.shoot, (shootdk.x, shootdk.y))
    			fenetre.blit(fantom1.fantom_face, (fantom1.x, fantom1.y))
    			fenetre.blit(vie, (0,0))
    			fenetre.blit(nombre, (32,32))			
    			pygame.display.flip()
    			time.sleep(0.30)		
    		
    
    
    		niveau.afficher (fenetre)				
    		nombre = font1.render('%d' %nb1, 1,(10,10,10))
    		fenetre.blit(epee.objet, (epee.x, epee.y))	
    		fenetre.blit(dk.direction, (dk.dkx, dk.dky)) #dk.direction = l'image dans la bonne direction
    		fenetre.blit(fantom1.fantom_face, (fantom1.x, fantom1.y))
    		fenetre.blit(vie, (0,0))
    		fenetre.blit(nombre, (32,32))		
    		pygame.display.flip()
    		
    
    
    
    					
    def event1 (dk, distanceA, nb1) :
    	# definition d'un event par une fonction
    	if distanceA < 25 :
    		
    		pygame.display.flip()
    		dk.epee = 1
    		epee.objet = pygame.image.load("transparent.png").convert_alpha()
    		nombre = font1.render('%d' %nb1, 1,(10,10,10))		
    		fenetre.blit(vie, (0,0))
    		fenetre.blit(nombre, (32,32))		
    		fenetre.blit(epee.objet, (epee.x, epee.y))	
    		fenetre.blit(dk.direction, (dk.dkx, dk.dky))
    		fenetre.blit(fantom1.fantom_face, (fantom1.x, fantom1.y))
    		pygame.display.flip()
    		
    
    	
    		
    
    
    def eventpnj (distanceB, dk,nb1):
    	# affiche un message lorsqu'il se rapproche du pnj
    	if dk.sous_niveau.structure[dk.case_y+dk.vitesse][dk.case_x] == "1" or dk.sous_niveau.structure[dk.case_y-dk.vitesse][dk.case_x] == "1" or dk.sous_niveau.structure[dk.case_y][dk.case_x-dk.vitesse] == "1" or dk.sous_niveau.structure[dk.case_y][dk.case_x+dk.vitesse] == "1" :
    			nombre = font1.render('%d' %nb1, 1,(10,10,10))		
    			fenetre.blit(vie, (0,0))
    			fenetre.blit(nombre, (32,32))		
    			fenetre.blit(epee.objet, (epee.x, epee.y))	
    			fenetre.blit(dk.direction, (dk.dkx, dk.dky)) 	
    			fenetre.blit(fantom1.fantom_face, (fantom1.x, fantom1.y))
    			fenetre.blit(text, (200, 370))
    			pygame.display.flip()
    
    
    def vie_supp (dk, nb1) :
    	if dk.sous_niveau.structure[dk.case_y][dk.case_x] == "2" :
    		dk.vita +=1
    		nombre = font1.render('%d' %nb1, 1,(10,10,10))		
    		fenetre.blit(vie, (0,0))
    		fenetre.blit(nombre, (32,32))		
    		fenetre.blit(epee.objet, (epee.x, epee.y))	
    		fenetre.blit(dk.direction, (dk.dkx, dk.dky))
    		pygame.display.flip()
    		
    def changement (dk,nb1,) :
    	if dk.sous_niveau.structure[dk.case_y][dk.case_x] == "a" :
    		dk.changement  = 1
    		dk.case_x = 1
    		dk.case_y = 9
    		dk.dkx = 32
    		dk.dky = 288
    		sous_niveau = Niveau(LV2_1)
    		sous_niveau.generer()
    		niveau = Niveau(LV2)
    		niveau.generer()
    		niveau.afficher (fenetre)
    		nombre = font1.render('%d' %nb1, 1,(10,10,10))		
    		fenetre.blit(vie, (0,0))
    		fenetre.blit(nombre, (32,32))		
    		fenetre.blit(epee.objet, (epee.x, epee.y))	
    		fenetre.blit(dk.direction, (dk.dkx, dk.dky))
    		pygame.display.flip()
    		global continuer
    		continuer = 3

    Merci pour votre aide :)

    • Partager sur Facebook
    • Partager sur Twitter
      19 mai 2014 à 21:36:37

      En fait, j'ai remarqué que le niveau 2 se générais bien, mais c'est la structure interne du personnage qui ne change pas, alors que la variable niveau change. Si vous pouviez m'aider, car je ne comprends pas pourquoi la variable self.niveau n'est pas actualisée dans la classe du personnage. De plus j'ai essayer de rajouter un ' dk = Perso(niveau, sous_niveau)' dasn la boucle de chargement, mais cela fait planter le programme ...

      • Partager sur Facebook
      • Partager sur Twitter

      problème de classe pour un jeu Pygame

      × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
      × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
      • Editeur
      • Markdown