Pysoya: menú de ejemplo

Dependencias: python-soya

Os dejo aquí una prueba que estoy haciendo de soya. Es una librería 3D libre para python en la que se programa a lo python (no os dejéis engañar por el código). Está hecho al vuelo en unas 4 horas.

Refinaré el código, ya que cuando empecé con él, no tenía ni idea de cómo iba soya Sad

Así que aquí lo dejo. Como ya sabréis, en opengl en GNU no se puede usar WGL para poner fuentes en 3D.

La idea es que cada letra del menú sea independiente para poder hacer todo tipo de efectos en 3d, desde ondas y demás. Ahora mismo he puesto MUY MUY MUY a lo guarro un seno asociado al item seleccionado.

No, no hace nada más aun, incluso hay que salir con CTRL-C, pero en un día más lo tengo correcto.

¿Hacemos el taeko como primer objetivo? En una semana lo tenemos, en dos a lo sumo.

Yo ahora tengo un poco más de tiempo, pero en no mucho vuelvo a España, así que no podré hacer nada. Venga, que alguien se anime.

Copiad y pegad y mirad un poco para ver cómo funciona soya y cómo NO hay que programar jamás en python.

Un saludo!

# brue (C) 2007
# GPLv2

import soya
import soya.label3d
import math

###########################################
X_POS = -0.5
Y_POS = 0.9
Z_POS = -1
X_SEP = 0.15
Y_SEP = -0.35

Z_CAM = 1.5

opciones = ["JUGAR", "SALIR","OPCION 3", "OPCION 4", "OP5"]
###########################################


class onechar(soya.Body):
    def __init__(self, world, c, x, y, z):
        self.x = x
        self.y = y
        self.z = z
        self.value = c
        self.rend = soya.label3d.Label3D(world, c)
        self.rend.set_xyz(x, y, z)
        self.rend.lit = 0
        soya.Body.__init__(self, world)

    def get_pos(self):
        return (self.x,self.y,self.z)
    
    def set_pos(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z
        self.rend.set_xyz(x, y, z)
        
    def get_value(self):
        return self.value
    
    def set_value(self, c):
        self.value = c
                   
                
    def debug(self):
        print self.get_value(), "->", self.get_pos()
        print "+++"
        
class onestring:
    def __init__(self, world, s, x, y, z, sep, sel=0):
        self.x = x
        self.y = y
        self.z = z
        self.selected=sel
        self.str = []
        self.sep = sep
        count = 0
        for c in s:
            self.str.append(onechar(world, c, self.x+(self.sep*count), self.y, self.z))                     
            count = count + 1
            
            
    def get_pos(self):
        return (self.x,self.y, self.z)

    def test_anim(self):
        for c in self.str:
            c.set_pos(c.get_pos[0],c.get_pos[1],c.get_pos[2]+0.01)

    def set_pos(self, x, y, z):
        count = 0
        for c in self.str:
            c.set_pos(x+(self.sep*count),y,z)
            count = count + 1

    def length(self):
        return len(self.str)
            
    def get_value(self):
        rstr = []
        for c in self.str:
            rstr.append(c.get_value())
        return rstr
            
    def set_value(self, s):
        self.str = []
        count = 0
        for c in s:
            newchar = onechar(c, self.x+(self.sep*count), self.y, self.z)
            self.str.append(newchar)
            count = count + 1

    def set_selected(self):
        self.selected = 1
        
    def unset_selected(self):
        self.selected = 0
        
    def selected(self):
        return self.selected
        
    def debug(self):
        for i in self.str:
            print i.debug()
            print "----"    
        
class menu_obj(soya.Body):
    def __init__(self, world, l, x,y,z, xsep, ysep):
        self.m = []
        self.xsep = xsep
        self.ysep = ysep
        self.mx = x
        self.my = y
        self.mz = z
        self. sel_index = 0
        count=0
        self.incre=0
        for c in l:
            self.m.append(onestring(world,c,x,y+(ysep*count),z,xsep))
            count = count + 1
        self.m[0].set_selected()
        soya.Body.__init__(self, world)

        
    def reset(self):
        self.m = []        
    
    def select(self, i):
        for os in self.m:
            os.unset_selected()
        self.m[i].set_selected()
        self.sel_index = i

    def reset_c(self, c, ind):
        cont = 0
        for carma in c:
            carma.set_pos(X_POS+(cont*X_SEP),Y_POS+(ind*Y_SEP),Z_POS)
            cont = cont + 1

        
    def advance_time(self, proportion):
        soya.Body.advance_time(self, proportion)
        if self.incre== 1: self.incre = -1
        for c in self.m[self.sel_index].str:
            c.rend.add_mul_vector(proportion,soya.Vector(self,0,0,((math.sin(self.incre))*0.01)))                  
        self.incre = self.incre + 0.1
        
        for event in soya.process_event():
            if event[0] == soya.sdlconst.MOUSEMOTION:
                self.mouse_posy = event[2]
                
                y_total = len(opciones)*Y_SEP
                for i in range(len(opciones)):
                    current_y = camera.coord3d_to_2d(soya.Point(self,X_POS+0.1,Y_POS+(i*Y_SEP),Z_POS))[1]
                    current_y_n = camera.coord3d_to_2d(soya.Point(self,X_POS+0.1,Y_POS+((i+1)*Y_SEP),Z_POS))[1]
                    
                    print "i:", i ,"-",current_y, "hasta ", current_y_n
                    print self.mouse_posy
                    if (self.mouse_posy > current_y) and (self.mouse_posy < current_y_n) and (i != self.sel_index):
                        self.reset_c(self.m[self.sel_index].str,self.sel_index)
                        self.sel_index=i

    def debug(self):
        for s in self.m:
            print s.debug()
 

if __name__ == "__main__":
    soya.init()
    
    scene = soya.World()
    
    menu = menu_obj(scene, opciones ,X_POS,Y_POS,Z_POS,X_SEP,Y_SEP)
    
    camera = soya.Camera(scene)
    camera.z = Z_CAM
    camera.fov = 100.0

    soya.set_root_widget(camera)
 
    print "---mainloop---"
    
    soya.MainLoop(scene).main_loop()

Comentarios

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de magmax

un detallito sin importancia

Aunque ya sé que lo vas a refinar y demás, tan sólo quería comentarte que, en python, hay que evitar los getters y setters (get_value/set_value). Razón aquí.

Miguel Ángel García
http://magmax.org

Imagen de Lk2

He estado leyendo el

He estado leyendo el artículo y mi paupérrimo nivel de inglés no me permite llegar a entender lo de los getters y setters. ¿Cómo funciona eso de "property" que he leído? ¿O es que "property" es el modo en que se acceden a las variables en Python.

I want to learn xD

Imagen de brue

getters y setters...

Un getter y un setter son los clase::get_loquesea() y case::set_loquesea(valor)

En python no tienen sentido porque siempre puedes cambiar tu idea de cómo acceder a las variables mientras que programas sin afectar a lo demás.

Un propiedad en python se define como una variable intrínsica de la propia clase (self.property = valor). Por eso se llama propiedad de la clase. Y se accede con clase.property ... sin preguntar a un método por el valor.

Un saludo.

--
·brue

brue

Imagen de Lk2

Eso ya

Pero eso es como en otros lenguajes.... por ejemplo en Java si defines todas las variables como públicas es el mismo comportamiento no?

Imagen de magmax

Python no es java

En absoluto.

Voy a poner un ejemplo un poco tonto, pero es lo único que se me ocurre. En una clase, por los motivos que sean, guardamos el día y mes actuales. Tenemos dos variables públicas llamadas "mes" y "dia". Desde otra clase, hacemos uso de estas variables.

Un buen día decidimos que este comportamiento es inaceptable, así que lo cambiamos por una única variable "día del año", y un par de métodos que me permitan obtener el día del mes y el mes propiamente dicho.

En este caso, si hemos usado Java, hay que retocar todas las llamadas a estos atributos públicos (por mal que suene, se llaman así).

Si hemos usado Python, no hay ningún problema. Se utilizan los accessors y en paz. Existirán las variables "mes" y "día" aunque serán, por decirlo de alguna manera, "virtuales". Es decir: cuando alguien llame al valor de la variable para obtener/asignar el valor, se llamará a una función que no tocará su valor, sino el de la variable "día del año". En otras palabras, seguiremos usando "clase.mes = 5" y "dia = clase.dia", que llamarán a métodos que obtienen el valor del dia a partir de "dia del año".

No sé si me he explicado.

Miguel Ángel García
http://magmax.org

Imagen de david.villa

No sé si lo conoces

pero viene al pelo del título de tu post:

Python Is Not Java

Muy interesante

No soy portavoz de ningún colectivo, grupo o facción. Mi opinión es personal e intransferible.

Imagen de brue

Y si ...

en un momento decides que lo quieres cambiar a getter y setters en Java? Reescribes todo. En java es casi una normal ocultar todo, la regla de la caja negra con entradas y salidas. En python, no. No está concebido de la misma forma. Así que pensar en python como se piensa en Java es un error.

--
·brue

brue

Imagen de Lk2

Malditos sean

La verdad yo nunca entendí bien el motivo que para hacer pública una variable privada o protegida en Java se hiciera con getters y setters.... realmente es más rápido hacerla pública, pero te dicen los "maestros" del lenguaje que queda feo ...

En python también pueden definirse las propiedades de una clase como privadas (haciéndolas llamarse __nombre en lugar de directamente nombre).

Eso también te obliga a usar getters y setters, jaja, pero viene bien para algunas cosas que no deben ser accesibles desde fuera o para las que solo quieres que haya getters y ningún setter

Imagen de david.villa

Depende

Lo de utilizar getter y setter no es para evitar la "fealdad". Es una forma de conseguir una interfaz más consistente. Muchas veces el valor que almacenas como atributo no es directamente utilizable por el cliente de la clase. Es habitual que en el momento de pedir o asignar el valor del atributo necesites hacer alguna comprobación o transformación (por ejemplo elevar una excepción si asignas una fecha imposible en el ejemplo de magmax) Eso te lo saltas si accedes directamente al valor del atributo.

La única forma de garantizar eso es ejecutando un método. Pero las propiedades de Python permiten ejecutar un método sin que el cliente de la clase tenga porqué saberlo. De todos modos, bajo mi punto de vista es una pérdida de tiempo intentar hacer interfaces a prueba de tontos, igual que no se pueden hacer lenguajes a prueba de tontos. Por ejemplo, eso de que Java te obliga a programar orientado a objetos es una fantasía. Yo he visto programas en Java en los que lo único que había era una clase con un método main de 2000 líneas. Si eso es orientado a objetos yo me bajo en la próxima estación. Y hay muchas más, como lo de que no se pueden hacer variables globales...

Si alguien lo quiere hacer mal (o no sabe hacerlo bien), da igual las "medidas anti-chapuzas" que pongas. La filosofía de Python es que todo es accesible y explícito. Si quieres usar bien una clase tienes que leer la documentación (esté hecha en lo que esté hecha), así que ¿para que sobrecargar el lenguaje con restricciones de acceso?

No soy portavoz de ningún colectivo, grupo o facción. Mi opinión es personal e intransferible.

Imagen de brue

Gracias!

No había leido esa web. Los quitaré, sólo molestan. También tengo que reescribir el lenght para cada objeto a la "python way".

Supongo que es lo malo de programar en C y Python... pero bueno, tomo el detalle, que creo que sí es importante. Gracias de nuevo, cualquier cosa que haga mejor el código es siempre muy muy muy bien recibido.

Por cierto, para todos los interesados en los juegos, estoy pensando que una buena idea sería hacer algo en vez de en 3D reales, hacer una mezcla sencilla con libcairo. Es decir, hacer un juego vectorial, completamente, escalable. Imagidad lo chulo que puede quedar un "Taeko" con gráficos entre 2d y 3d pero vectoriales siempre. Contamos con la fuerza del svg, que es un formato que se ha puesto las pilas en los últimos años. Yo ya me lo imagino con sus tranparencias sus "cosicas así pequeñicas delicás", sus ... y siempre se pueden poner bitmaps. De los que se puede hacer uno con gran resolución y luego escalar según convenga Smiling Como escribir un plugin en python es trivial, se podría hacer algo para ponerle las congas de nintendo como control alternativo. ¿¿Alguien me saca un PFC de este tipo??

Un saludo!

--
·brue

brue

Imagen de Vigilante

Sobre tu PFC

"Labas" Brue, tus ideas sobre videojuegos hazselas llegar a Carlos Morcillo, que creo sería la persona que podría estar más interesada o si te va el tratamiento de formas 3D, podrías contactar con Antonio Adán.