#!coding: utf-8
"""
Ce code est une légère simplification pythonique du code gl_brick.py
En utilisant la structure "with"
with permet de mettre en évidence un code qui fait une action "au début"
et une action "à la fin"
un glPushMatrix() va quasi toujours se finir par un glEndMatrix()
, avec le with, on dit simple :
"le code qui suit commence par un push et finit par un pop"
Et ce quoiqu'il arrive (une exception est lancée, voir chapitre sur les exceptions)
"""
from __future__ import print_function, division
import pygame
import random
# importer la bibliothèque OpenGL !
from OpenGL.GL import *
from OpenGL.GLU import *
pygame.init()
class PushPop:
def __enter__(self):
glPushMatrix() # quand on entre : push
def __exit__(self, a,b,c):
glPopMatrix() # quand on sort : push
class BeginEnd:
def __init__(self, mode):
self.mode = mode
def __enter__(self):
glBegin(self.mode)
def __exit__(self, a,b,c):
glEnd()
def nouvel_ecran():
e = pygame.display.set_mode(taille, pygame.DOUBLEBUF | pygame.OPENGL | pygame.RESIZABLE)
glViewport(0, 0, taille[0], taille[1])
glEnable(GL_COLOR_MATERIAL)
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
glEnable(GL_NORMALIZE)
glShadeModel(GL_SMOOTH)
glLight(GL_LIGHT0, GL_AMBIENT, (0,0,0,1))
glLight(GL_LIGHT0, GL_DIFFUSE, (1,1,1,1))
glLight(GL_LIGHT0, GL_SPECULAR, (1,1,1,1))
glEnable(GL_DEPTH_TEST)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
return e
taille = [12*60, 500]
ecran = nouvel_ecran()
clock = pygame.time.Clock()
ROUGE = [255,0,0]
VERT = [0,255,0]
BLEU = [0,0,255]
JAUNE = [255,255,0]
BLANC = [255,255,255]
NOIR = [0, 0, 0]
ORANGE = [255, 153, 0]
BLEU_CLAIR = [135, 206, 250]
class Balle:
pass
balles = []
for i in range(5):
b = Balle()
b.taille = 20
b.x = random.randrange(700 - b.taille)
b.y = 300 + random.randrange(200)
b.sx = random.choice([-1,1])
b.sy = random.choice([-1,1])
balles.append(b)
class Brique:
pass
briques = []
for i in range(12):
for j in range(5):
r = Brique()
r.vie = 3
r.taille_x = 60
r.taille_y = 30
r.x = i * r.taille_x
r.y = j * r.taille_y
briques.append(r)
def draw_cube():
"""
from (0,0,0) to (1,1,1)
faces are ccw (counter clockwise : sens contraire des aiguilles d'une montre)
"""
with BeginEnd(GL_TRIANGLES): # GL_QUADS is deprecated
glNormal3f(0, 0, 1) # up
glVertex3f(0, 0, 1)
glVertex3f(1, 0, 1)
glVertex3f(0, 1, 1)
glVertex3f(1, 0, 1)
glVertex3f(1, 1, 1)
glVertex3f(0, 1, 1)
glNormal3f(0, 0, -1) # down
glVertex3f(0, 0, 0)
glVertex3f(0, 1, 0)
glVertex3f(1, 0, 0)
glVertex3f(0, 1, 0)
glVertex3f(1, 1, 0)
glVertex3f(1, 0, 0)
glNormal3f(1, 0, 0) # right
glVertex3f(1, 0, 0)
glVertex3f(1, 1, 0)
glVertex3f(1, 0, 1)
glVertex3f(1, 1, 0)
glVertex3f(1, 1, 1)
glVertex3f(1, 0, 1)
glNormal3f(-1, 0, 0) # left
glVertex3f(0, 0, 0)
glVertex3f(0, 0, 1)
glVertex3f(0, 1, 0)
glVertex3f(0, 0, 1)
glVertex3f(0, 1, 1)
glVertex3f(0, 1, 0)
glNormal3f(0, 1, 0) # back
glVertex3f(0, 1, 0)
glVertex3f(0, 1, 1)
glVertex3f(1, 1, 0)
glVertex3f(0, 1, 1)
glVertex3f(1, 1, 1)
glVertex3f(1, 1, 0)
glNormal3f(0, -1, 0) # front
glVertex3f(1, 0, 0)
glVertex3f(1, 0, 1)
glVertex3f(0, 0, 0)
glVertex3f(1, 0, 1)
glVertex3f(0, 0, 1)
glVertex3f(0, 0, 0)
t = 0
fini = 0
while fini == 0:
# pour tous les événements qui se sont passsés depuis la dernière fois
for event in pygame.event.get():
if event.type == pygame.QUIT: # si l'event est de type QUIT
fini = 1 # on met fini à 1, ce qui va quitter la boucle à la fin de ce tick
elif event.type == pygame.VIDEORESIZE:
# on s'adapte à la nouvelle fenêtre
taille = [event.w, event.h]
ecran = nouvel_ecran() # re créer l'écran !
# déplacement
for b in balles:
b.x += b.sx * 5
b.y += b.sy * 5
i = 0
while i < len(briques):
r = briques[i]
if not(
r.x > b.x + b.taille or
r.y > b.y + b.taille or
r.x + r.taille_x < b.x or
r.y + r.taille_y < b.y
):
b.x -= b.sx * 5
b.y -= b.sy * 5
dx = r.x - b.x if r.x > b.x else b.x - (r.x + r.taille_x)
dy = r.y - b.y if r.y > b.y else b.y - (r.y + r.taille_y)
if dx > dy:
b.sx *= -1
else:
b.sy *= -1
r.vie -= 1
if r.vie == 0:
del briques[i]
i -= 1
i += 1
if b.x > taille[0] - b.taille:
b.sx = -1
if b.x < 0:
b.sx = 1
if b.y > taille[1] - b.taille:
b.sy = -1
if b.y < 0:
b.sy = 1
t += 1
# dessin
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(45, 1.0 * taille[0] / taille[1], 100, 2000) # fov 45°, ratio taille[0] / taille[1], distance min : 100, distance max : 2000
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
# position et orientation de la camera :
camera_x = taille[0]/2 # au milieu de l'arène
camera_y = -taille[1] # derrière l'arène
camera_z = 700 # bien haut
cible_camera_x, cible_camera_y = taille[0]/2, taille[1]/2 # regarde le milieu de l'arène
cible_camera_z = 0 # regarde par terre
gluLookAt(camera_x, camera_y, camera_z, cible_camera_x, cible_camera_y, cible_camera_z, 0,0,1)
# position de la lampe :
light_x, light_y = taille[0] / 2, taille[1] / 2 # au milieu de l'arène
light_z = 150 # un peu au dessus des briques (de taille 100)
glLight(GL_LIGHT0, GL_POSITION, [light_x, light_y, light_z, 1])
# dessin du sol
glColor3ubv(BLEU_CLAIR) # 3ubv signifie que l'on indique la couleur avec une liste de 3 int de 0 à 255
with BeginEnd(GL_TRIANGLES): # GL_QUADS is deprecated
glNormal3f(0, 0, 1)
glVertex3f(0, 0, 0)
glVertex3f(taille[0], 0, 0)
glVertex3f(taille[0], taille[1], 0)
glVertex3f(0, taille[1], 0)
# dessin des 4 côtés
glColor3f(0.8, 0.8, 0.8) # 3f signifie que l'on indique la couleur avec 3 float (nombres réels / à virgule) entre 0 et 1
with PushPop():
glTranslatef(0, -50, 0)
glScalef(taille[0], 50, 50)
draw_cube()
with PushPop():
glTranslatef(0, taille[1], 0)
glScalef(taille[0],50,50)
draw_cube()
with PushPop():
glTranslatef(-50, 0, 0)
glScalef(50, taille[1], 50)
draw_cube()
with PushPop():
glTranslatef(taille[0], 0, 0)
glScalef(50, taille[1], 50)
draw_cube()
# dessin des briques
for r in briques:
color = (ROUGE if r.vie == 3 else
VERT if r.vie == 2 else
JAUNE)
glColor3ubv(color)
with PushPop():
d = 5
glTranslatef(r.x + d, taille[1] - (r.y + d) - (r.taille_y - 2*d), 0)
glScalef(r.taille_x - 2*d, r.taille_y - 2*d, 100)
draw_cube()
# dessin des balles
glColor3ubv(ORANGE)
for b in balles:
with PushPop():
glTranslatef(b.x, taille[1] - b.y - b.taille, 0)
glScalef(b.taille, b.taille, b.taille)
draw_cube()
# dessin du repère en (0,0,100) (sans lighting)
glDisable(GL_LIGHTING)
with PushPop():
glTranslatef(0,0,100)
glScalef(50,50,50)
with BeginEnd(GL_LINES):
glColor3ubv(ROUGE)
glVertex3f(0, 0, 0)
glVertex3f(1, 0, 0)
glColor3ubv(VERT)
glVertex3f(0, 0, 0)
glVertex3f(0, 1, 0)
glColor3ubv(BLEU)
glVertex3f(0, 0, 0)
glVertex3f(0, 0, 1)
glPointSize(5)
with BeginEnd(GL_POINTS):
glColor3ubv(ROUGE)
glVertex3f(1, 0, 0)
glColor3ubv(VERT)
glVertex3f(0, 1, 0)
glColor3ubv(BLEU)
glVertex3f(0, 0, 1)
glEnable(GL_LIGHTING)
# appliquer les dessins
pygame.display.flip()
clock.tick(60)
pygame.quit()