Je viens vous proposer un petit exercice "SpaceBall" niveau débutant inspiré de mes lectures sur le site pygame.
Pour faire cet exercice il faut avoir lu les deux premières parties du tutoriel sur python de 6pr1 et prolixe.
Il faut également avoir lu les deux premiers chapitres du tutoriel sur pygame de clemms.
C'est fait? Alors on va pouvoir s'y mettre!!
But de l'exercice:
Le but de cet exercice tout simple est d'obtenir le déplacement aléatoire d'une planète dans un plan (une fenêtre).
Et, ensuite, euh... Bah c'est tout! (Exercice de débutant je vous ai dit!! )
Déroulement du programme:
Une fenêtre doit s'ouvrir au lancement du programme avec un fond representant l'espace.
A l'ouverture de la fenêtre la planète doit se déplacer automatiquement.
Dès que la planète touche le bord de la fenêtre, hop, elle rebondie sur le bord et repart en sens inverse.
Comme je suis très sympa , je vous donne conne cette magnifique image de la galaxie Andromède (au format 640x480):
Téléchargez-là, ce sera notre fond!
Et puis tant qu'on y est, je vous donne aussi l'image d'une belle planète bleue.
Téléchargez-là aussi ce sera notre Space Ball!!
Bien, vous avez tout ce qu'il faut pour faire cet exercice!
Un peu d'aide?
Eh oui, je sais ce que c'est de vouloir faire un exercice mais de pas savoir comment s'y prendre!!
On a souvent besoin d'un petit coup de pied au... d'avoir le pied à l'étrier, pour pouvoir s'en sortir!
Je suis passé par là (d'ailleurs j'y suis encore pour certaines approches de python )
Bon, tout d'abord il faut générer la fenêtre (à la bonne taille), charger l'image de notre galaxie et la coller comme fond.
Ensuite il faut charger notre planète, et récupérer son rect.
Ensuite on peut passer à notre boucle "while 1":
On récupère les évènements de type "QUIT" pour fermer la fenêtre si besoin.
A ce stade, on peut commencer à s'occuper des mouvement de notre planète.
On va pour cela utiliser move qui prends les coordonnées de déplacement de notre rect en paramètre
On va donc avoir quelque chose du style planete.move(x,y)
x et y correspondent aux déplacement sur l'axe X et l'axe Y. Ces variables doivent donc etre initialisées avant la boucle while.
Sauf que si on s'arrête là, notre space ball va sortir de la fenêtre!! Bah oui, on dit:
tant que 1:
Bouge la planète de (1,3) ((1,3) c'est un exemple hein)
Mais on n'a pas spécifié de limite!! Donc notre planète va se déplacer de x=1 et y=3 indéfiniment!! Elle va rapidement sortir de la fenêtre!! Bon ils vous restera la galaxie d'Andromede à contempler mais c'est pas ça qu'on veut!!
On doit donc ici incorporer une condition:
1ere condition:
Si le bord gauche de notre rect est < à ...
0!! Et oui, n'oubliez pas que une Surface avec pygame ça fonctionne avec des coordoonées. Les coordoonées du point tou en haut à gauche sont (0,0).
ou
2eme condition:
Si le bord droit de notre rect est > à ... (allez un petit effort!)
la largeur max de notre surface: 640!!
Alors
On inverse la le déplacement sur x.
Il ne vous reste plus qu'à faire la même chose pour l'axe des y et c'est quasi fini!
N'oubliez pas de coller votre image galaxie sur la fenêtre,
et de coller votre planète sur les nouvelles coordonnées de son déplacement
Une petit rafraichissement d'image et hop c'est tout bon!!
Et voilà une belle planète terre qui rebondie partout dans la galaxie!!!
Si il y en a parmi vous qui veulent modifier ou améliorer l'exercice ( générer d'autres contraintes etc.) et proposer leur code pour les autres Zéros ils sont les bienvenus!
J'espère que, comme moi, vous aurez pris plaisir à faire ce petit exercice!
(Je mettrai mon code en correction un peu plus tard.)
Bon python à tous les Zéros!! Postez vos codes!!
PS: Je proposerai bien ce code dans le billet "exercices python" du forum, mais je ne sais pas si il faut un accord des modérateurs et/ou des admins du site, don en attendant, j'ouvre ce topic.
l'image de la terre n'est pas idéalement cropée, faudrait enlever 4 pix à droite et 1 en bas
le code ci-dessous en tiend compte astuce:
ce code fonctionnne parce que l'image totale de la terre dépasse de 1 pix le dessin de la terre et que le déplacement est de 1 pix aussi, ce qui fait qu'il n'y a pas de trainée même si l'on n'update que l'image de la terre.
from pygame import *
space = image.load('space.jpg') # chargement de l'image de l'espace
space_rect = space.get_rect() # rectangle de l'image de l'espace
earth = image.load('earth.png') # chargement de l'image de la terre
earth_rect = earth.get_rect() # rectangle de l'image de la terre
earth_rect.w = earth_rect.w - 4 # pour rattraper le crop trop large
earth_rect.h = earth_rect.h - 1 # pour rattraper le crop en hauteur
screen = display.set_mode(space_rect.size) # surface de rendu a la taille de l'image de l'espace
display.update(screen.blit(space,(0,0))) # affichage de l'image de l'espace
earth_rect.center = space_rect.center # on place la terre au centre de la fenetre
ticks = time.Clock() # tempo
vx,vy = 1,1 # verteurs de deplacement de la terre
while not event.peek(QUIT): # tant qu'on quitte pas
event.clear() # on evite de saturer la file d'evenements
# on efface l'image de terre en affichant a la place le bout d'espace correspondant
screen.blit(space,earth_rect,earth_rect)
# si la terre VA sortir du cadre on change de direction
if not space_rect.contains(earth_rect.inflate(-2,-2).move(vx,0)): vx = -vx
if not space_rect.contains(earth_rect.inflate(-2,-2).move(0,vy)): vy = -vy
# on deplace la terre
earth_rect.move_ip((vx,vy))
# on affiche la terre a sa nouvelle position
display.update(screen.blit(earth,earth_rect))
ticks.tick(80) # tempo
Salut josmiley!
Je n'ai pas bien compris à quoi tu a pu voir que l'image de la terre n'était pas bien "croppé"
Je suis un débutant en pygame , va falloir que tu m'explique deux, trois trucs dans ton code
earth_rect.w = earth_rect.w - 4
Le ".w" est-elle une fonction propre eu rect? N'importe quel rect peut avoir cette fonction ".w" qui spécifiera donc systématiquement la largeur du rect?
screen = display.set_mode(space_rect.size)
Même question pour le ".size" . Est-ce aussi une fonction propre au rect?
if not space_rect.contains(earth_rect.move(vx,0)): vx = -vx
earth_rect est un objet Rect et w est un de ses attributs magiques.
les differents attributs d'un Rect( que j'appel magiques parce que je n'ai pas encore trouvé comment réaliser la même chose en python) sont:
x, y, top, left, bottom, right, topleft, bottomleft, topright, bottomright, midtop, midleft, midbottom, midright, center, centerx, centery, size, width, height, w et h.
Citation : pygame.org
Rect.contains(Rect): return bool
Returns true when the argument is completely inside the Rect.
bon, c'est vrai que j'ai un peu compliqué le code ...
earth_rect est un objet Rect et w est un de ses attributs magiques.
les differents attributs d'un Rect( que j'appel magiques parce que je n'ai pas encore trouvé comment réaliser la même chose en python)...
Comme ça :
class Rectangle(object):
def __init__(self, x, y, w, h):
self.x = x
self.y = y
self.w = w
self.h = h
@property
def size(self):
return (self.w, self.h)
@size.setter
def size(self, val):
self.w, self.h = val
@property
def center(self):
return (self.x + self.w//2, self.y + self.h//2)
Edit: bon ok, désolé, je me suis fait un peu de pub. Pour arrêter le HS, je pense que je vais proposer une solution demain si j'ai le temps de m'en occuper, promis.
from pygame import *
space = image.load('space.jpg') # chargement de l'image de l'espace
space_rect = space.get_rect() # rectangle de l'image de l'espace
earth = image.load('earth.png') # chargement de l'image de la terre
earth_rect = earth.get_rect() # rectangle de l'image de la terre
earth_rect.w = earth_rect.w - 4 # pour rattraper le crop trop large
earth_rect.h = earth_rect.h - 1 # pour rattraper le crop en hauteur
screen = display.set_mode(space_rect.size) # surface de rendu a la taille de l'image de l'espace
display.update(screen.blit(space,(0,0))) # affichage de l'image de l'espace
earth_rect.center = space_rect.center # on place la terre au centre de la fenetre
ticks = time.Clock() # tempo
vx,vy = 1,1 # verteurs de deplacement de la terre
while not event.peek(QUIT): # tant qu'on quitte pas
event.clear() # on evite de saturer la file d'evenements
# on efface l'image de terre en affichant a la place le bout d'espace correspondant
screen.blit(space,earth_rect,earth_rect)
# si la terre sort du cadre on change de direction
if earth_rect.left < space_rect.left or earth_rect.right > space_rect.right: vx = -vx
if earth_rect.top < space_rect.top or earth_rect.bottom > space_rect.bottom: vy = -vy
# on deplace la terre
earth_rect.move_ip((vx,vy))
# on affiche la terre a sa nouvelle position
display.update(screen.blit(earth,earth_rect))
ticks.tick(80) # tempo
Salut.
Bon je n'ai pas le temps de faire mon code ce matin (vu que josmiley a proposé la version "simple", je pense que je vais en faire une orientée objet, héritant de DirtySprite...), mais j'en ai quand même profité pour retoucher un peu l'image de la Terre avec Gimp, et faire en sorte qu'elle soit correctement centrée (et un tout petit peu moins floue) :
Ok, je crois que j'ai pigé les attributs "magiques"!
Entre les explications josmiley et NoHar, je m'y retrouve.
D'alleurs je vais aller jeter un coup d'oeil au tuto de NoHar.
Par contre je n'ai toujours pas compris comment tu a pu voir le mauvais crop de l'image terre. T'as grossi l'aimage 2000000 fois?
Attention il demande quand même une certaine pratique de la POO en Python, hein.
J'imagine bien, mais bon, par curiosité, et puis j'aime bien apprendre des trucs moi
Je mets mon code comme correction. J'ai essayé d'être le plus raccord possible avec le cours de clemms sur pygame.
J'ai integré le time.Clock() que joesmiley à montré dans son code (pratique pour contrôler les déplacements, je ne connaissais pas).
J'ai aussi volontairement fait un code "basique" pour qu'il soit facilement compréhensible par les débutant en python/pygame.
Donc ce code n'est certainement pas optimisé mais j'ai envie de dire, c'est fait exprès!
Allez, zou! La correction:
#!usr/bin/env/python
# -*- coding:utf-8 -*-
import pygame
from pygame import *
pygame.init() # Initalisation des modules de pygame
hauteur=480
largeur=640
taille=(largeur,hauteur) # On stocke les dimensiosn de la fenêtre dans un tuple
Fenetre=pygame.display.set_mode(taille) # On affiche la fenêtre
Fond=pygame.image.load("galaxy_640_480.jpg").convert() # on charge l'image de la galaxie
Terre = pygame.image.load("earth.png") # On charge l'image de la planète
TerreRect = Terre.get_rect()
deplacement_terre_x=1 # On définit une coordoonée de déplacement sur l'axe des x
deplacement_terre_y=1 # On définit une coordoonée de déplacement sur l'axe des y
horloge=pygame.time.Clock() # On charge un objet Clock pour pouvoir ensuite controler le déplacement da planète
continuer=1
while continuer: # Boucle infinie
for event in pygame.event.get(): # On gère les évènement de type QUIT pour fermer la fenêtre
if event.type==QUIT:
continuer=0
TerreRect = TerreRect.move(deplacement_terre_x,deplacement_terre_y) # On déplace la terre des coordonnées x et y définis à la ligne 21-22
if TerreRect.left < 0 or TerreRect.right > largeur: # Si les côtés du rect de la planète sortent des dimensions de la fenêtre
deplacement_terre_x= -deplacement_terre_x # Oniverse le déplacement sur x
if TerreRect.top < 0 or TerreRect.bottom > hauteur: # Si les côtés du rect de la planète sortent des dimensions de la fenêtre
deplacement_terre_y= -deplacement_terre_y # Oniverse le déplacement sur y
horloge.tick(90) # On limite le déplacement de la terre à 90 frames apr secondes
Fenetre.blit(Fond,(0,0)) # Les raffraîchissements d'usage...
Fenetre.blit(Terre,TerreRect)
pygame.display.flip()
EDIT: Je suis étonné que la partie "exercice" du forum python soit si peu etoffée...
Vu le nombre de zéros sur le forum qui assure en python, c'est un peu dommage...
Moi qui ne suis pas un pro de python, ni un informaticien , je trouve que l'une des premières difficulté que l'on rencontre après avoir lu un (des) cours sur python, c'est de trouver des exercices ou des thèmes d'exercices pour progresser et s'améliorer.
Je suis étonné que la partie "exercice" du forum python soit si peu etoffée...
Vu le nombre de zéros sur le forum qui assure en python, c'est un peu dommage...
Moi qui ne suis pas un pro de python, ni un informaticien , je trouve que l'une des premières difficulté que l'on rencontre après avoir lu un (des) cours sur python, c'est de trouver des exercices ou des thèmes d'exercices pour progresser et s'améliorer.
C'est dû à la jeunesse du forum, je pense.
On a de la chance parce qu'on s'est organisés pour faire des sujets d'exos sympas dès le départ, mais le problème reste que le forum étant jeune, et les volontaires pour créer les sujets étant aussi occupés (je suis passé modo entre temps... je passe donc beaucoup moins de temps sur le forum Python qu'avant, puisque c'est l'un des plus propres, ce qui me laisse moins de temps pour créer des exos ou des mini-projets...), il est vrai que ça peut manquer un peu de dynamisme. Mais c'est grâce à des initiatives comme la tienne sur ce topic que l'on peut arranger ça.
Oui effectivement si le forum est relativement jeune ça peut expliquer qu'il n'y ai pas beaucoup d'exercices proposés. Je me souviens avoir posé la question d'un forum python, à l'époque où il n'y avait pas de forum python .
Le problème pour des gens comme moi qui ne sommes pas des brutes en programmation, c'est qu'il est difficile d'évaluer la pertinence d'un exercice que l'on pense proposer, mais bon qui ne tente tien n'a rien en même temps.
Est-ce qu'on peut proposer l'exo SpaceBall dans la partie "exercices" du forum?
@joesmiley: Marrant le coup de la planète qui rebondit, je vais essayer de comprendre ton code pour m'y retrouver.
#!/usr/bin/env python
#coding: utf8
import pygame
class Terre(pygame.sprite.Sprite):
"""Classe héritière de Sprite"""
def __init__(self, surface, size):
pygame.sprite.Sprite.__init__(self) # init de la classe parent
# image et rect sont des attributs de Sprite
self.image = surface
self.rect = surface.get_rect()
self.size = size # un tuple des dimensions
self.vector = [1, 1] # la vitesse [x, y]
def deplacement(self):
# On déplace la terre sur x et y
self.rect.x += self.vector[0];self.rect.y += self.vector[1]
# On vérifie s'il y a collision avec le bord de l'écran
# si oui on inverse les valeurs
if self.rect.right >= self.size[0] or self.rect.left <= 0:
self.vector[0] = -self.vector[0]
if self.rect.bottom >= self.size[1] or self.rect.top <= 0:
self.vector[1] = -self.vector[1]
def update(self):
self.deplacement()
if __name__ == "__main__":
pygame.init()
size = (640, 480)
screen = pygame.display.set_mode(size)
background = pygame.image.load("bg.jpg").convert()
surface_terre = pygame.image.load("terre.png").convert_alpha()
terre = Terre(surface_terre, size) # Création de l'objet Terre
sprites_terre = pygame.sprite.RenderUpdates((terre)) # Création d'un RenderUpdate qui prend comme paramètre notre objet Terre
run = True
fps = pygame.time.Clock()
while run:
fps.tick(90)
event = pygame.event.poll()
if event.type == pygame.QUIT:
run = False
screen.blit(background, background.get_rect())
sprites_terre.update() # On met à jour notre Sprite
sprites_terre.draw(screen) # On le dessine sur l'écran
pygame.display.flip()
Argh, j'me suis encore fait couper l'herbe sous le pied (le badge bleu, c'est comme la kryptonite)...
Oups.... ma faute, je n'ai fait que survoler les posts sans vraiment lire :S
Citation : NoHaR
je pense que je vais en faire une orientée objet, héritant de DirtySprite...
Sinon (n'aillant, pour l'instant, encore jamais utilisé de DirtySprite je vais peut-être dire une connerie mais bon) cela pourrait être intéressant de voir les différences d'utilisation entre un Sprite et un DirtySprite sur cette exo, si toutefois il y en a ?
Merci pour ce code F@rhen , mais je suis un peu largué!!
Je débute dans la création et l'utilisation des classes, je vais essayer de piger un peu ton code malgré tout.
Par contre je me disais que si on propose un petit exercice comme celui-là sur le post-it "exercice du forum", je le verrai bien dans un style progressif, afin que les bons gros Zéros (comme moi ) s'y retrouvent. Avec des parties liées mais découpées pour que la compréhension et l'apprentissage soient relativement aisées. Genre:
1/ Générer le script de base permettant le déplacement de la SPaceBall dans une fenêtre
2/ Rajouter une ou deux contraintes dans le style de ce qu'a proposé joesmiley avec une variable accélération qui augment sur l'axe des y
3/ Générer une classe pour commencer à coder un peu objet
4/ Comme le propose NoHar, gérer les collisions etc
Bon si mon idée est pourrie vous avez le droit de me le dire hein!
Bon F@rhen je me suis saigné quelques jours sur ton code mais c'est un peu trop hardu pour moi, pour que je me débrouille tout seul...
Par contre j'ai essayé de coder cette exercice en créant une petite classe Planete, histoire de coder un peu en POO, mais je ne sais pas trop dans quel ordre m'y prendre.
Je ne sais pas vraiment quoi mettre dans la classe. Par exemple, je ne sais absolument pas quoi mettre dans le constructeur de la classe. J'ai crée une méthode déplacement(), mais je n'arrive pas à l'utiliser correctement...
Je vous mets mon code (qui ne fonctionne pas du tout ), histoire que vous voyez l'étendu du désastre:
#!usr/bin/env/python
# -*- coding:utf-8 -*-
import pygame
from pygame import *
class Planete:
def deplacement(self):
TerreRect = TerreRect.move(deplacement_terre_x,deplacement_terre_y) # On déplace la terre des coordonnées x et y
if TerreRect.left < 0 or TerreRect.right > largeur: # Si les côtés du rect de la planète sortent des dimensions de la fenêtre
deplacement_terre_x = -deplacement_terre_x # Oniverse le déplacement sur x
if TerreRect.top < 0 or TerreRect.bottom > hauteur: # Si les côtés du rect de la planète sortent des dimensions de la fenêtre
deplacement_terre_y = -deplacement_terre_y # Oniverse le déplacement sur y
if __name__=="__main__":
pygame.init()
hauteur=480
largeur=640
taille=(largeur,hauteur)
Fenetre=pygame.display.set_mode(taille)
Fond=pygame.image.load("galaxy_640_480.jpg").convert()
Terre = pygame.image.load("earth.png").convert()
Terre=Terre.get_rect()
deplacement_terre_x=1
deplacement_terre_y=1
horloge=pygame.time.Clock()
continuer=1
while continuer:
for event in pygame.event.get(): # On gère les évènement de type QUIT pour fermer la fenêtre
if event.type==QUIT:
continuer=0
# A partir d'ici je patine complètement...
# Je n'arrive pa à utiliser la classe Planete correctement...
TerreRect = Planete()
horloge.tick(90) # On limite le déplacement de la terre à 90 frames apr secondes
Fenetre.blit(Fond,(0,0)) # Les raffraîchissements d'usage...
Fenetre.blit(Terre,TerreRect.deplacement())
pygame.display.flip()
Du coup ma classe ne contient pas de constructeur...
Un petit coup de main pour m'aider à coder la classe Planete proprement serait le bienvenu!
Avant de poster un message, vérifiez la date du sujet dans lequel vous comptiez intervenir.
Si le dernier message sur le sujet date de plus de deux mois, mieux vaut ne pas répondre. En effet, le déterrage d'un sujet nuit au bon fonctionnement du forum, et l'informatique pouvant grandement changer en quelques mois il n'est donc que rarement pertinent de déterrer un vieux sujet.
Au lieu de déterrer un sujet il est préférable :
soit de contacter directement le membre voulu par messagerie privée en cliquant sur son pseudonyme pour accéder à sa page profil, puis sur le lien "Ecrire un message"
soit de créer un nouveau sujet décrivant votre propre contexte
ne pas répondre à un déterrage et le signaler à la modération
Je ferme ce sujet. En cas de désaccord, me contacter par MP.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.