Rasthor | (j'ai changé le titre, ça fait moins pompeux )
Je me suis mis sérieusement au Python et je viens d'achever mon premier code original hier soir, donc c'est un peu la fête.
Enfin original est un bien grand mot, puisque je n'ai fait que retranscrire mot pour mot, variables pour variables, un programme Rebol, qui était donné en exemple dans un numéro de Login (Numéro 14 de Septembre 2002, pages 76-77).
Le principe du programme est bêtement un moteur de Raycasting, comme celui de Wolfenstein premier du nom.
Un screenshot () :
Il faut aussi télécharger cette image:
http://img71.exs.cx/img71/421/degrade8ag.gif
Ca met un dégradé en fond d'image. Il faut le sauver sur le disque, le placer dans le même dossier que le script et le renommer en "degrade.gif".
Enfin bref, voici le code:
Code :
- #########################
- # #
- # Moteur de Raycasting #
- # #
- #########################
- # Import de Tkinter et des fonctions trigo utilisees
- from Tkinter import *
- from math import cos, radians
- # Definition des variables
- px = 9 * 1024
- py = 11 * 1024
- stride = 5 # pas de deplacement
- heading = 0 # angle de vue
- turn = 10 # nombre de degres par rotation
- # Definition du labyrinthe.
- # 0 = sol ou l'on peut se deplacer
- # Plus grand que 0 = mur, et le chiffre defini la couleur
- laby = [[ 8, 7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 7],
- [ 7, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 8],
- [ 8, 0, 0, 0, 12, 0, 0, 0, 14, 0, 9, 7],
- [ 7, 0, 0, 0, 12, 0, 4, 0, 13, 0, 0, 8],
- [ 8, 0, 4, 11, 11, 0, 3, 0, 0, 0, 0, 7],
- [ 7, 0, 3, 0, 12, 3, 4, 3, 4, 3, 0, 8],
- [ 8, 0, 4, 0, 0, 0, 3, 0, 3, 0, 0, 7],
- [ 7, 0, 3, 0, 0, 0, 4, 0, 4, 0, 9, 8],
- [ 8, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 7],
- [ 7, 0, 5, 6, 5, 6, 0, 0, 0, 0, 0, 8],
- [ 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7],
- [ 8, 7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 7]]
- # Palette de couleur. La valeur du mur defini la valeur de la couleur.
- palette = ["#000080","#008000","#008080",
- "#000080","#800080","#808000","#C0C0C0",
- "#808080","#0000FF","#00FF00","#FFFF00",
- "#0000FF","#FF00FF","#00FFFF","#FFFFFF"]
- # Table des cosinus precalcules. On gagne un peu en vitesse.
- ctable = []
- for a in range(0,(359+180)):
- ctable.append(int((cos(radians(a))*1024)/10))
- # Fonction pour trouver le cosinu de l'angle v.
- def getangle(v):
- return ctable[v+1]
- #####################################
- #
- # Moteur principal du raycasting
- #
- def retrace():
- # On efface le labyrinthe
- can1.delete('rectangle')
- # On initialise les valeurs
- xy1x = 0
- xy1y = 0
- xy2x = 0
- xy2y = 0
- angle = heading-44 % 360
- if angle < 0:
- angle = angle+360
- # On parcout les 90 degres de l'angle de vue.
- # On lance un rayon xx/yy et des qu'il touche un mur,
- # on affiche un rectangle
- for a in range(angle,angle+89):
- xx = px
- yy = py
- stepx = getangle(a+90)
- stepy = getangle(a)
- l = 0
- while 1:
- xx = xx-stepx
- yy = yy-stepy
- l = l+1
- colonne = int(xx/1024)
- ligne = int(yy/1024)
- # Instruction de controle:
- # la boucle s'arrete si le rayon touche un mur (<> 0).
- if laby[ligne][colonne] <> 0:
- break
- # On calcule la hauteur du rectangle
- h = int(900/l)
- xy1y = 100-h
- xy2y = 100+h
- # Le rectangle fait 3 pixels de largeur
- xy2x = xy1x + 3
- # On determine la couleur du rectangle
- color = palette[laby[ligne][colonne]]
- # On affiche le rectangle et on recommence
- can1.create_rectangle(xy1x, xy1y, xy2x, xy2y, fill=color,outline=color,tag='rectangle')
- xy1x = xy2x+1
- ##################################
- #
- # Gestionnaire d'evenements :
- #
- # On determine les 4 fonctions possibles: avancer, reculer, tourner la tête
- # à droite et tourner la tête à gauche.
- def depl_avance(event):
- global px, py
- # On avance selon le pas "stride" determie au debut.
- # On calcul le cosinus de l'angle en question.
- newpx = px - getangle(heading+90)*stride
- newpy = py - getangle(heading)*stride
- c = int(newpx/1024)
- l = int(newpy/1024)
- # On controle si l'on peut se deplacer.
- if laby[l][c] == 0:
- px = newpx
- py = newpy
- retrace()
- def depl_recule(event):
- global px, py
- newpx = px - getangle(heading+90)*stride*-1
- newpy = py - getangle(heading)*stride*-1
- c = int(newpx/1024)
- l = int(newpy/1024)
- if laby[l][c] == 0:
- px = newpx
- py = newpy
- retrace()
- def turn_left(event):
- global heading
- heading = (heading + (360 -turn)) % 360
- retrace()
- def turn_right(event):
- global heading
- heading = (heading + turn) % 360
- retrace()
- # Creation du canvas:
- fen1 = Tk()
- can1 = Canvas(fen1,bg="dark grey", height=200, width=360)
- # On charge le degrade de fond. C'est une image gif.
- # A ameliorer: degrade directement en python.
- if open("degrade.gif" ):
- photo = PhotoImage(file="degrade.gif",width=360, height=200)
- item = can1.create_image(0, 0, anchor=NW, image=photo)
- can1.pack()
- # On trace une premiere fois le labyrinthe
- retrace()
- # Liaison des evenements
- fen1.bind("<Up>",depl_avance)
- fen1.bind("<Down>",depl_recule)
- fen1.bind("<Left>",turn_left)
- fen1.bind("<Right>",turn_right)
- # demarrage du receptionnaire d'evenements (boucle principale) :
- fen1.mainloop()
|
Faut encore que je fasse un degradé en fond d'écran (quelqu'un saurait-il faire ceci ?), que je fusionne les commande avance et recule et que je le commente un peu plus.
Sinon des avis sur le code en lui-même ? Des idées d'amélioration, d'optimisation ?
PS: le code pour le copier coller directement:
#########################
# #
# Moteur de Raycasting #
# #
#########################
# Import de Tkinter et des fonctions trigo utilisees
from Tkinter import *
from math import cos, radians
# Definition des variables
px = 9 * 1024
py = 11 * 1024
stride = 5 # pas de deplacement heading = 0 # angle de vue
turn = 10 # nombre de degres par rotation
# Definition du labyrinthe.
# 0 = sol ou l'on peut se deplacer
# Plus grand que 0 = mur, et le chiffre defini la couleur
laby = [[ 8, 7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 7],
[ 7, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 8],
[ 8, 0, 0, 0, 12, 0, 0, 0, 14, 0, 9, 7],
[ 7, 0, 0, 0, 12, 0, 4, 0, 13, 0, 0, 8],
[ 8, 0, 4, 11, 11, 0, 3, 0, 0, 0, 0, 7],
[ 7, 0, 3, 0, 12, 3, 4, 3, 4, 3, 0, 8],
[ 8, 0, 4, 0, 0, 0, 3, 0, 3, 0, 0, 7],
[ 7, 0, 3, 0, 0, 0, 4, 0, 4, 0, 9, 8],
[ 8, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 7],
[ 7, 0, 5, 6, 5, 6, 0, 0, 0, 0, 0, 8],
[ 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7],
[ 8, 7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 7]]
# Palette de couleur. La valeur du mur defini la valeur de la couleur.
palette = ["#000080","#008000","#008080",
"#000080","#800080","#808000","#C0C0C0",
"#808080","#0000FF","#00FF00","#FFFF00",
"#0000FF","#FF00FF","#00FFFF","#FFFFFF"]
# Table des cosinus precalcules. On gagne un peu en vitesse.
ctable = []
for a in range(0,(359+180)):
ctable.append(int((cos(radians(a))*1024)/10))
# Fonction pour trouver le cosinu de l'angle v.
def getangle(v):
return ctable[v+1]
#####################################
#
# Moteur principal du raycasting
#
def retrace():
# On efface le labyrinthe
can1.delete('rectangle')
# On initialise les valeurs
xy1x = 0
xy1y = 0
xy2x = 0
xy2y = 0
angle = heading-44 % 360
if angle < 0:
angle = angle+360
# On parcout les 90 degres de l'angle de vue.
# On lance un rayon xx/yy et des qu'il touche un mur,
# on affiche un rectangle
for a in range(angle,angle+89):
xx = px
yy = py
stepx = getangle(a+90)
stepy = getangle(a)
l = 0
while 1:
xx = xx-stepx
yy = yy-stepy
l = l+1
colonne = int(xx/1024)
ligne = int(yy/1024)
# Instruction de controle:
# la boucle s'arrete si le rayon touche un mur (<> 0).
if laby[ligne][colonne] <> 0:
break
# On calcule la hauteur du rectangle
h = int(900/l)
xy1y = 100-h
xy2y = 100+h
# Le rectangle fait 3 pixels de largeur
xy2x = xy1x + 3
# On determine la couleur du rectangle
color = palette[laby[ligne][colonne]]
# On affiche le rectangle et on recommence
can1.create_rectangle(xy1x, xy1y, xy2x, xy2y, fill=color,outline=color,tag='rectangle')
xy1x = xy2x+1
##################################
#
# Gestionnaire d'evenements :
#
# On determine les 4 fonctions possibles: avancer, reculer, tourner la tête
# à droite et tourner la tête à gauche.
def depl_avance(event):
global px, py
# On avance selon le pas "stride" determie au debut.
# On calcul le cosinus de l'angle en question.
newpx = px - getangle(heading+90)*stride
newpy = py - getangle(heading)*stride
c = int(newpx/1024)
l = int(newpy/1024)
# On controle si l'on peut se deplacer.
if laby[l][c] == 0:
px = newpx
py = newpy
retrace()
def depl_recule(event):
global px, py
newpx = px - getangle(heading+90)*stride*-1
newpy = py - getangle(heading)*stride*-1
c = int(newpx/1024)
l = int(newpy/1024)
if laby[l][c] == 0:
px = newpx
py = newpy
retrace()
def turn_left(event):
global heading
heading = (heading + (360 -turn)) % 360
retrace()
def turn_right(event):
global heading
heading = (heading + turn) % 360
retrace()
# Creation du canvas:
fen1 = Tk()
can1 = Canvas(fen1,bg="dark grey", height=200, width=360)
# On charge le degrade de fond. C'est une image gif.
# A ameliorer: degrade directement en python.
if open("degrade.gif" ):
photo = PhotoImage(file="degrade.gif",width=360, height=200)
item = can1.create_image(0, 0, anchor=NW, image=photo)
can1.pack()
# On trace une premiere fois le labyrinthe
retrace()
# Liaison des evenements
fen1.bind("<Up>",depl_avance)
fen1.bind("<Down>",depl_recule)
fen1.bind("<Left>",turn_left)
fen1.bind("<Right>",turn_right)
# demarrage du receptionnaire d'evenements (boucle principale) :
fen1.mainloop() Message édité par Rasthor le 04-03-2005 à 23:57:50
|