-
Etape 5 : Notre premier PNJ
Etape 5 : Mon premier PNJ
1. L’objet Rect
2. Mise à niveau du code
3. Création
4. Animation
5. Interaction
1. Généralités : l’objet Rect :
Jusqu'à présent nous avons fonctionné de façon quelque peu basique, avec des images (qui sont des Surfaces) que nous placions et déplacions a notre guise. Pour nous diriger petit à petit vers les fonctionnalités qui nous intéressent , nous allons désormais revoir notre système d’objets en utilisant des objets Rect, car ceux-ci possèdent des attributs riches et nous permettrons une meilleur interaction avec notre monde.
Une Objet Rect de Pygame est comme son nom l’indique un rectangle, celui-ci possède les attributs suivants :
top, left, bottom, right
topleft, bottomleft, topright, bottomright
midtop, midleft, midbottom, midright
center, centerx, centery
size, width, height
w,h
Ces attributs peuvent être représentés visuellement ainsi :
Ce sont eux qui vont nous permettre une grande souplesse dans le positionnement et dans la détection des collisions (nous y viendrons un peu plus tard dans cet article).
Pour définir un objet Rect j’utilise la méthode suivante :
mon_rectangle = pygame.Rect (x, y, longueur, hauteur)
Exemple : mon_carré = pygame.Rect (10, 10, 20, 30)
Sera donc un carré positionné en X = 10, Y = 10, de longueur 20 et hauteur 30
2 : Mise a niveau du code :
Reprenons le code de l’Etape2 , nous avions ceci :
perso = pygame.image.load('boy.png').convert_alpha()
x = 150
y = 250
Désormais je vais pouvoir déclarer mon personnage différemment :
perso = pygame.image.load('boy.png').convert_alpha()
perso_rect = pygame.Rect(150,250,200,335)
je créé un nouvel objet perso_rect ( j’aurais pu l’appeler autrement ), que je déclare comme étant un objet Rect de Pygame avec les caractéristique ( X=150,Y=250) , les memes valeurs que dans mon ancien code, ceci me permet de garder son positionnement initial, et d’une largeur de 50 et hauteur de 85, qui sont la taille de mon image
Longueur 200 – 150(qui est la position initiale X) = 50
Hauteur 335 – 250(qui est la position initiale Y) =85
Pour afficher mon personnage , j’avais le code :
screen.blit(perso,(x,y))
J’utilise désormais l’objet perso_rect qui contient les coordonnées de positionnement :
Screen.blit(perso, perso_rect)
Testons notre code :
L’affichage est identique.
!!! Mais mon personnage ne se déplace plus !
C’est normal nous utilisions les positions (x,y) dans l’ancien script pour afficher l’image a ces coordonnés avec la méthode blit. A présent nous n’avons plus ces variables, mais nous avons à la place les valeurs X et Y de notre objet ‘perso_rect’. Ce sont ces valeurs que nous allons utiliser à la place
if key[K_LEFT]:
perso_rect.x-=1
if key[K_RIGHT]:
perso_rect.x+=1
if key[K_UP]:
perso_rect.y-=1
if key[K_DOWN]:
perso_rect.y+=1
perso_rect.x à une valeur de 150 et perso_rect.y de 250, car nous les avons déclaré dans la création de notre objet perso_rect = pygame.Rect(150,250,200,335)
Notre nouveau code :
import pygame,sys
from pygame import *
pygame.init()
screen = pygame.display.set_mode((800,600))
background = pygame.image.load('fond.png').convert()
perso = pygame.image.load('boy.png').convert_alpha()
perso_rect = pygame.Rect(150,250,200,335)
while True: # Boucle principale du jeu
key=pygame.key.get_pressed()
for event in pygame.event.get():
if event.type == QUIT:
sys.exit()
if key[K_LEFT]:
perso_rect.x-=1
if key[K_RIGHT]:
perso_rect.x+=1
if key[K_UP]:
perso_rect.y-=1
if key[K_DOWN]:
perso_rect.y+=1
screen.blit(background,(0,0))
screen.blit(perso,perso_rect)
pygame.display.flip()
3. Notre premier PNJ :
Pas trop tôt !!
Pour faire simple, nous allons faire la même chose que pour notre Héro, une déclaration on ne peut plus simple d’un objet Rect qui contiendra sa position :
pnj = pygame.image.load('pnj.png').convert_alpha()
pnj_rect = pygame.Rect(500,400,550,485)
Et nous l’affichons en fin de script avec
screen.blit(pnj,pnj_rect)
4. Animation de notre PNJ: (en cours d’écriture)
Un peu trop statique à notre goût, donnons un peu vie à notre PNJ, nous aimerions qu’il vadrouille tranquillement tant que nous n’interagissons pas avec lui. Faisons le se déplacer de façon aléatoire.
Nous voulons que notre PNJ de place latéralement sur une surface de 150 pixels, sa position initiale étant de X = 500, il se déplacera jusqu'à X = 650 maximum et fera des aller et retour sur cette distance.
import pygame,sys,random
from pygame import *
pygame.init()
screen = pygame.display.set_mode((800,600))
background = pygame.image.load('fond.png').convert()
perso = pygame.image.load('boy.png').convert_alpha()
perso_rect = pygame.Rect(150,250,200,335)
pnj = pygame.image.load('pnj.png').convert_alpha()
pnj_rect = pygame.Rect(500,400,550,485)
clock=pygame.time.Clock()
moveleft = False
moveright = False
while True: # Boucle principale du jeu
key=pygame.key.get_pressed()
for event in pygame.event.get():
if event.type == QUIT:
sys.exit()
if key[K_LEFT]:
perso_rect.x-=1
if key[K_RIGHT]:
perso_rect.x+=1
if key[K_UP]:
perso_rect.y-=1
if key[K_DOWN]:
perso_rect.y+=1
if moveleft == False:
moveright = True
if moveright == True:
pnj_rect.x+=1
if pnj_rect.x == 650 :
moveleft = True
moveright = False
if moveright == False:
moveleft = True
if moveleft == True:
pnj_rect.x-=1
if pnj_rect.x == 500 :
moveleft = False
moveright = True
screen.blit(background,(0,0))
screen.blit(pnj, pnj_rect)
screen.blit(perso,perso_rect)
pygame.display.flip()
clock.tick(60)
- Interraction :
Ok il est bien beau nôtre PNJ mais il ne fait pas grand-chose, nous aimerions qu’il puisse interagir avec notre Héro.
- Quand notre Héro est proche de lui, il devra s’arrêter de marcher et lui parler. Si notre personnage s’éloigne alors notre PNJ repartira vaquer à ses occupations.
Pour détecter si notre personnage est assez proche du PNJ, nous allons utiliser la détection des collisions entre deux rectangles, car nos personnages étant des objets Rect, pygame met a notre disposition une fonction de détection d’intersection entre deux objets Rect.
Rect.colliderect(Rect) : retourne Vrai ou Faux
Que j’applique à nos deux personnages avec une condition dans la boucle principale de mon programme
if perso_rect.colliderect(pnj_rect)== True :
dialogue = 1
elif perso_rect.colliderect(pnj_rect)== False :
dialogue = 0
Et cette action qu’elle est elle ? Nous décidons que notre PNJ va parler à notre héro et lui demander d’effectuer une petite quête, donc si la collision entre notre Héro et notre PNJ est Vraie : nous initialisons une variable ‘dialogue’, si la collision n’est plus vérifiée, nos personnages étant trop loin pour discuter, la valeur de ‘dialogue’ est nulle.
La variable dialogue doit être créée avec la boucle du programme ( dialogue = 0 )
Pour discuter nous avons besoin d’initialiser une Police de caractère et de l’afficher.
ma_police = pygame.font.SysFont('t4cbeaulieux', 16)
Et je créé ma condition :
if dialogue == 1:
Quete_texte = ma_police.render('Pourriez vous aller au moulin ?',True, (255,255,255))
screen.blit(Quete_texte, (pnj_rect.x-20,pnj_rect.y-20))
else :
screen.blit(background,(0,0))
Résumé : si la collision est détectée, Dialogue = 1, le PNJ parle, sinon rien ne s’affiche
Vérifions en lançant notre programme :
En route pour l’aventure !
Bon maintenant je veux que mon Héro aille au moulin ! et réalise qu’il n’y à personne, et revienne le dire au PNJ .
Mais comment notre PNJ va-t-il s’avoir que nous sommes bien allé au moulin ?
->Tout simplement en créant une variable qui s’initialisera lorsque nous serons au moulin.
Oui mais comment savoir que notre personnage est bien au moulin ?
-> E n détectant une collision entre notre Héro et le moulin
Oui mais le moulin fait parti du fond de l’écran ? Ce n’est pas un rectangle ou un Objet du jeu ?
-> Trichons, et créons un rectangle transparent autour du rectangle, nous pourrons ainsi déclarer une collision.
Nous allons déclarer une variable Quête = 0, ce sera l’étape dans la progression de notre Quête, si le personnage va au moulin, celle-ci passera a Quête = 1. Ainsi lorsque notre Héro reviendra voir le PNJ celui-ci saura si oui ou non nous sommes bien allé au moulin.
Créons notre rectangle pour le Moulin :
moulin = pygame.Rect (130,460,40,60)
moulinimg = pygame.Surface((40,60))
moulinimg.set_alpha(0) # On rend la surface transparente
et une detection de collision entre le Moulin et le Héro , moyen de savoir que le héro est au bon endroit :
if (perso_rect.colliderect(moulin)) == True:
Quete_texte = ma_police.render('Hum , personne ici..',True, (255,255,255))
screen.blit(Quete_texte, (perso_rect.x-20,perso_rect.y-20))
Quete = 1
Notez qu’on itinialise la valeur de Quete à 1 si il y a collision. Donc l’ensemble du code :
import pygame,sys
from pygame import *
pygame.init()
screen = pygame.display.set_mode((800,600))
background = pygame.image.load('fond.png').convert()
perso = pygame.image.load('boy.png').convert_alpha()
perso_rect = perso.get_rect()
pnj = pygame.image.load('pnj.png').convert_alpha()
pnj_rect = pygame.Rect(500,400,550,485)
ma_police = pygame.font.SysFont('t4cbeaulieux', 16)
dialogue = 0 # ici la variable dialogue
Quete = 0 # ici l’étape de la quête
moulin = pygame.Rect (130,460,40,60) # On créé un objet Rect
moulinimg = pygame.Surface((40,60)) # On y associe une surface
moulinimg.set_alpha(0) # et on rend le tout transparent
while 1: # Boucle principale du jeu
posx,posy = pygame.mouse.get_pos()
key=pygame.key.get_pressed()
screen.blit(background,(0,0))
for event in pygame.event.get():
if event.type == QUIT:
sys.exit()
if key[K_LEFT]:
perso_rect.x-=1
if key[K_RIGHT]:
perso_rect.x+=1
if key[K_UP]:
perso_rect.y-=1
if key[K_DOWN]:
perso_rect.y+=1
if perso_rect.colliderect(pnj_rect)== True :
dialogue = 1
elif perso_rect.colliderect(pnj_rect)== False :
dialogue = 0
if dialogue ==1: # Si l’on est en collision , le PNJ parle
if Quete== 0 : # Si on est pas encore allé au moulin
Quete_texte = ma_police.render('Pourriez vous aller au moulin ?',True, (255,255,255))
screen.blit(Quete_texte, (pnj_rect.x-20,pnj_rect.y-20))
if Quete == 1 : # Si l’on y deja allé au moulin
Quete_texte = ma_police.render('Ou diable est il encore allé...',True, (255,255,255))
screen.blit(Quete_texte, (pnj_rect.x-20,pnj_rect.y-20))
else : # se declanchera si l’on est plus en colision
screen.blit(background,(0,0))
if (perso_rect.colliderect(moulin)) == True: #collision Moulin/Hero
Quete_texte = ma_police.render('Hum , personne ici..',True, (255,255,255))
screen.blit(Quete_texte, (perso_rect.x-20,perso_rect.y-20))
Quete = 1 # On donne la valeur de 1 a Quete
screen.blit(moulinimg, moulin) # on affiche le Rect moulin invisible
screen.blit(pnj,pnj_rect)
screen.blit(perso,perso_rect)
pygame.display.set_caption("X = %s Y = %s " % (posx,posy))
pygame.display.flip()
Voila en gros pour le système d’interaction, qui nous a permis de voir comment détecter des collisions, et de communiquer avec notre héro.
Comme vous vous en doutez, si l’on multiplie les dialogues et les quêtes, notre code va devenir un joyeux champ de bataille.
Nous allons voir dans notre prochain chapitre comment organiser cela un petit peu mieux. Grâce aux Modules et aux fichiers textes.
Tags : pnj, pygame, collision
-
Commentaires