[Tutor PyCZ] Help

Petr Prikryl PrikrylP na skil.cz
Středa Únor 22 08:46:05 CET 2006


Úvodem, neznám Livewires, takže se na to dívám
jako externista.

geon napsal...
> [...] Taky bych zkusil naznačit jak se zbavit 
> toho "proklatého" ;-) global v první funkci:
> 
> def vyrobHrace():
>     xh=random.randint(0, 630)
>     yh=random.randint(0, 479)
>     Hrac_telo = circle( xh, yh, 5, filled=1)
>     return xh, yh, Hrac_telo
> 
> 
> xh, yh, Hrac_telo= vyrobHrace()
> 
> while 1:
>     klavesy = keys_pressed()
>     xh, yh = posunHrace(xh, yh)
>     if "q" in klavesy:
>         break
> [...]

A pak už je to jen krůček k používání tříd.
Kdykoliv se dá něco personifikovat, je to 
dobrý kandidát pro instanci nějaké třídy...

class Hrac(object):
    """Třída pro objekt hráče."""

    def __init__(self, x, y):
        """Při vytváření hráče se zadává počáteční pozice."""
        self.x = x
        self.y = y
        self.telo = circle(self.x, self.y, 5, filled=1)

    def posunRel(dx, dy):
        """Relativní posun v souřadnicích."""
        self.moveAbs(self.x + dx, self.y + dy)

    def posunAbs(x, y):
        """Posun na absolutní souřadnice."""
        self.x = x
        self.y = y
        # Tady nevím, jak je v původním příkladu
        # realizována funkce move_to(), ale mohlo
        # by to být použito nějak takto:
        move_to(self.telo, self.x, self.y)

Hráč by se pak vyrobil nějak takto:

    hrac = Hrac(random.randint(0, 630),
                random.randint(0, 479))

A posunoval by se takto:

    hrac.posunRel(+1, 0)

Další problém, který vidím v původním zdrojovém textu
spočívá v tom, že se testuje moc kláves najednou a 
po testu každé klávesy se počká...

    if "8" in klavesy:
        yh=yh+1
        move_to(Hrac_telo, xh, yh)
        sleep(1)
    if "9" in klavesy:
        xh=xh+1
        yh=yh+1
        move_to(Hrac_telo, xh, yh)
        sleep(1)
[...]

    if "3" in klavesy:
        yh=yh-1
        xh=xh+1
        move_to(Hrac_telo, xh, yh)
        sleep(1)

Správně by se v ostatních větvích mělo použít elif,
to znamená, že po úspěšném testu by se měly provést
příslušné příkazy a dál už nic (jen ten sleep jedenkrát).

Protože vždycky testujeme jednu z osmi kláves
a výsledkem je zjištění, o kolik se máme posunout
ve směru x a o kolik ve směru y (tj. o +1, 0 nebo -1).
Pokud vím přesně, kterou klávesu chci obsloužit
(tedy ne množinu kláves, ale jen jednu), pak může 
být výhodné předem nadefinovat a potom využívat
takovouto tabulku:

    delta = { "1": (-1, -1),
              "2": ( 0, -1),
              "3": (+1, -1),
              "4": (-1,  0),
              "5": ( 0,  0),  # viz dále
              "6": ( 0, +1),
              "7": (-1, +1),
              "8": ( 0, +1),
              "9": (+1, +1),
            }

A cyklus by pak vypadal nějak takto:

    klavesy = keys_pressed()  # nebo jiná inicializace
    while "q" not in klavesy:
        for k in klavesy:
            dx, dy = delta[k]
            hrac.moveRel(dx, dy)

            # Šlo by taky napsat...
            # d = delta[k]
            # hrac.moveRel(d)

            # ... nebo jednoduše
            # hrac.moveRel(delta[k])

        sleep(1)
        klavesy = keys_pressed()

S tím for je to ještě zbytečně zamotané. Dalo by se to
dále vylepšit. Kdyby například existovala funkce, která 
by vracela buď číselnou klávesu nebo "q", mohla by v případě
nestisknutí žádné klávesy vracet například "5" (žádný 
posun). Výsledný cyklus by pak vypadal takto:

    k = "5"
    while k != "q":
        hrac.moveRel(delta[k])
        sleep(1)
        k = stiknutaKlavesa()

Pro testování kolizí se dají přímo testovat vnitřní
proměnné objektu hrac.x a hrac.y, které nahrazují
původní xh a yh. Případně se dá nadefinovat metoda
třídy Hrac takto:

         def kolize(self, x, y):
             return (self.x == x) and (self.y == y)

a pak někde použít...

    if hrac.kolize(x, y):
        akce("Byl jsi sežrán robotem.")

pepr

P.S. Nezkoušel jsem to. Budou tam asi chyby.


Další informace o konferenci Tutor