Du må være registrert og logget inn for å kunne legge ut innlegg på freak.no
X
LOGG INN
... eller du kan registrere deg nå
Dette nettstedet er avhengig av annonseinntekter for å holde driften og videre utvikling igang. Vi liker ikke reklame heller, men alternativene er ikke mange. Vær snill å vurder å slå av annonseblokkering, eller å abonnere på en reklamefri utgave av nettstedet.
  4 717
Hei,

Sitter å knoter litt med pygame. Har lagt meg et lite "spill", men har støtt på et problem. Ved flytting av NPC-er, har jeg laget en sjekk for å være sikker på at de holder seg innenfor skjermen. Denne sjekken blir kjørt en gang for hver NPC pr. frame gjennom funksjonen update:

Kode

 def update(self, npcs = None):
        self.movepos[1] = self.speed

        turn = rand()
        if turn < 0.07:
            self.movepos[0] += 0.2*PI*rand()
        elif turn < 0.14:
            self.movepos[0] -= 0.2*PI*rand()
        if npcs != None:
            self.change_direction(npcs)

        dx = cos(self.movepos[0])*self.movepos[1]
        dy = sin(self.movepos[0])*self.movepos[1]
        newpos = self.rect.move((dx, dy))
        
        if not self.area.contains(newpos):
            tl = not self.area.collidepoint(newpos.topleft)
            tr = not self.area.collidepoint(newpos.topright)
            bl = not self.area.collidepoint(newpos.bottomleft)
            br = not self.area.collidepoint(newpos.bottomright)

            # NOTE:
            # Also checking that the direction is in fact against
            # a wall, ensuring its not moving away from it. This because
            # it could have turned around during the previous frame, but not
            # got far away enough to escape the walls
            
            top = tr and tl and sin(self.movepos[0]) <= 0
            bottom = br and bl and sin(self.movepos[0]) >= 0
            left = tl and bl and cos(self.movepos[0]) <= 0
            right = tr and br and cos(self.movepos[0]) >= 0

            if top or bottom:
                self.movepos[0] = -self.movepos[0]
                self.rect = self.rect.move(self.movepos)
            elif left or right:
                self.movepos[0] = PI - self.movepos[0]
                self.rect = self.rect.move(self.movepos)
            else:
                self.rect = newpos
        else:
            self.rect = newpos
        pygame.event.pump()
Hvor:
movepos[0] er vinkel
movepos[1] er hastighet

I mine øyner skulle denne sjekken fungere, da den både sjekker hvilken del av NPC-en som er ute av skjermen (top, bottom, left eller right) og om vinkelen faktisk peker mot den aktuelle kanten av skjermen.

Likevel så fungerer dette ikke, da NPC-en plutselig kan finne på å rote seg bort, utenfor skjermen. Er det noen som klarer å se hva som er problemet her?

Hvis dere har andre tips til forbedring av koden så tar jeg gjerne i mot dem også. Vedlagt ligger hele koden, inkludert sprites.

Testet med Python 2.6.6 og pygame 1.9.1, men det burde fungere på andre versjoner også.
Kan begynne med at før spillet terminerer burde du kjøre en
"pygame.display.quit()", slik at pygame-vinduet blir absluttet. Slik det var nå bare frøys hele skjermen når jeg prøvde å avslutte, og jeg måtte manuelt skrive det inn i IDLE for å avslutte vinduet.

Kode

            if top or bottom:
                self.movepos[0] = -self.movepos[0]
                self.rect = self.rect.move(self.movepos)
            elif left or right:
                self.movepos[0] = PI - self.movepos[0]              
                self.rect = self.rect.move(self.movepos)
Du sier at self.move pos er vinkel + hastighet. Men slik jeg husker rect.move (og slik jeg forstår dokumentasjonen), så skal den ha inn et offset med X og Y koordinater. Noe som gjør at disse tallene blir noe merkelige. Leger og merke til at bevegelsene er veldig merkelig i det det skjer kollisjoner, noe som ser ut til at kan være derfor? Personlig liker jeg å bruker Vektorer, og ikke "rektangler" for å holde på possisjonene til sprites, da det er lettere å drive med matematikk rundt vektorer om de er implementert så de har støtte for de vanlige matemtiske funksjonene. Dermed kan du f.eks. ha en vektor med possisjonen, og en annen for bevegelse, så er det bare å addere disse for å få den nye possisjonen.

Endret det slik:

Kode

            if top or bottom:
                self.movepos[0] = -self.movepos[0]
                dx = cos(self.movepos[0])*self.movepos[1]
                dy = sin(self.movepos[0])*self.movepos[1]
                self.rect = self.rect.move(dx, dy)
            elif left or right:
                self.movepos[0] = PI - self.movepos[0]
                dx = cos(self.movepos[0])*self.movepos[1]
                dy = sin(self.movepos[0])*self.movepos[1]
                self.rect = self.rect.move(dx, dy)
            else:
                self.rect = newpos
Jeg ser at jeg bruker samme kode der flere plasser for å regne ut dx og dy, dette burde du kanskje legge inn i en egen metode eller noe. Anyways, bevegelsene virker nå mer naturlige, og de "hopper" ikke hver gang de dulter i veggen. Men det kom en annen rar bug hvor plutselig wizarden + en prinsesse bare låse seg inntil veggen og stod og hoppet frem og tilbake, med noen få pixler mellomrom. Ikke helt fått sjekket hvorfor det skjer. Men anntar det har noe med at han har vision av prinsessa som står inntil veggen og ikke får angrepet ho eller noe i den duren.
Sist endret av etse; 12. desember 2011 kl. 07:17.
1. d4
steili's Avatar
Trådstarter
Sitat av etse Vis innlegg
Kan begynne med at før spillet terminerer burde du kjøre en
"pygame.display.quit()", slik at pygame-vinduet blir absluttet. Slik det var nå bare frøys hele skjermen når jeg prøvde å avslutte, og jeg måtte manuelt skrive det inn i IDLE for å avslutte vinduet.
Vis hele sitatet...
Takk for tipset. Nå slipper jeg å restarte IDLE for hver gang jeg glemmer meg, og kjører programmet fra IDLE
Du sier at self.move pos er vinkel + hastighet. Men slik jeg husker rect.move (og slik jeg forstår dokumentasjonen), så skal den ha inn et offset med X og Y koordinater. Noe som gjør at disse tallene blir noe merkelige. Leger og merke til at bevegelsene er veldig merkelig i det det skjer kollisjoner, noe som ser ut til at kan være derfor? Personlig liker jeg å bruker Vektorer, og ikke "rektangler" for å holde på possisjonene til sprites, da det er lettere å drive med matematikk rundt vektorer om de er implementert så de har støtte for de vanlige matemtiske funksjonene. Dermed kan du f.eks. ha en vektor med possisjonen, og en annen for bevegelse, så er det bare å addere disse for å få den nye possisjonen.

Endret det slik:

Jeg ser at jeg bruker samme kode der flere plasser for å regne ut dx og dy, dette burde du kanskje legge inn i en egen metode eller noe.
Vis hele sitatet...
Se der ja.. Slik kan det gå når man ser seg blind på kode Dette hjalp jo veldig, og alt ser bra ut nå.
Anyways, bevegelsene virker nå mer naturlige, og de "hopper" ikke hver gang de dulter i veggen. Men det kom en annen rar bug hvor plutselig wizarden + en prinsesse bare låse seg inntil veggen og stod og hoppet frem og tilbake, med noen få pixler mellomrom. Ikke helt fått sjekket hvorfor det skjer. Men anntar det har noe med at han har vision av prinsessa som står inntil veggen og ikke får angrepet ho eller noe i den duren.
Vis hele sitatet...
Bugen er fikset. Problemet oppstod på grunn av at jeg krevde at wizardenspriten skulle dekke over hele prinsessen. Ute ved kantene ble det litt krøll, så jeg endret til at det holder at rektanglene kolliderer.

Hvilken vektorklasse bruker du? Mener jeg husker å ha skrevet en 2DVector-klasse tidligere når jeg har puslet med pygame. Ville jo nesten trodd det følgte med en slik klasse med pygame, men jeg finner i hvert fall ingen i pygame.locals.

Takk for hjelpen - jeg tar gjerne i mot flere tips.

Kode

# Basic 2D-vector class
class Vector2D:
    def __init__(self, x, y):
        self.x = float(x)
        self.y = float(y)
        
    def __repr__(self):
        return "Vector(%s, %s)" % (self.x, self.y)
            
    def __add__(self, b):
        return Vector2D(self.x + b.x, self.y + b.y)

    def __sub__(self, b):
        return Vector2D(self.x - b.x, self.y - b.y)

    def __mul__(self, b):
        # TO DO: Add cross-product between vectors
        return Vector2D(self.x * b, self.y * b)

    def __div__(self, b):
        return Vector2D(self.x / b, self.y / b)

    def magnitude(self):
        return float(math.sqrt(self.x ** 2 + self.y ** 2))

    def radians(self):
        vector = self.normalized()
        return math.atan2(vector.y, vector.x)

    def degrees(self):
        vector = self.normalized()
        return math.atan2(vector.y, vector.x)*180/math.pi

    def normalized(self):
        m = self.magnitude()
        if m!=0:
            return Vector2D(self.x / m, self.y / m)
        else:
            return Vector2D(0,0)
    
    def copy(self):
        return Vector2D(self.x, self.y)
Min selvskrevne versjon av en Vektor som jeg bruker i de fleste spill og oppgaver. Har ikke implementert kryss-produkt enda da jeg ikke har hatt bruk for det. Skal være lett å utvide den om det er behov.
1. d4
steili's Avatar
Trådstarter
Sitat av etse Vis innlegg

Kode

# Basic 2D-vector class
class Vector2D:
    def __init__(self, x, y):
        self.x = float(x)
        self.y = float(y)
        
    def __repr__(self):
        return "Vector(%s, %s)" % (self.x, self.y)
            
    def __add__(self, b):
        return Vector2D(self.x + b.x, self.y + b.y)

    def __sub__(self, b):
        return Vector2D(self.x - b.x, self.y - b.y)

    def __mul__(self, b):
        # TO DO: Add cross-product between vectors
        return Vector2D(self.x * b, self.y * b)

    def __div__(self, b):
        return Vector2D(self.x / b, self.y / b)

    def magnitude(self):
        return float(math.sqrt(self.x ** 2 + self.y ** 2))

    def radians(self):
        vector = self.normalized()
        return math.atan2(vector.y, vector.x)

    def degrees(self):
        vector = self.normalized()
        return math.atan2(vector.y, vector.x)*180/math.pi

    def normalized(self):
        m = self.magnitude()
        if m!=0:
            return Vector2D(self.x / m, self.y / m)
        else:
            return Vector2D(0,0)
    
    def copy(self):
        return Vector2D(self.x, self.y)
Min selvskrevne versjon av en Vektor som jeg bruker i de fleste spill og oppgaver. Har ikke implementert kryss-produkt enda da jeg ikke har hatt bruk for det. Skal være lett å utvide den om det er behov.
Vis hele sitatet...
Den så veldig bra ut. Takk for den.