pygame sprite problem: linksherum oder rechtsherum drehen

Hier werden alle anderen GUI-Toolkits sowie Spezial-Toolkits wie Spiele-Engines behandelt.
Antworten
Benutzeravatar
HorstJENS
User
Beiträge: 124
Registriert: Donnerstag 9. Februar 2006, 21:41
Wohnort: Wien, Österreich
Kontaktdaten:

liebe Python/Pygame-Gurus,
könnt ihr mir bitte das Brett vor meinem Kopf entfernen welches mich daran hindert folgendes Problem zu lösen:

Das kleine schwarze Viereck (sprite pirat1) soll selbstständig entscheiden ob es sich linksrum oder rechtsrum dreht um zu dem (zufällig positioinierten) grünen Kreuz zu fahren. Derzeit dreht es manchmal richtig herum, manchmal falsch herum. Es sollte die jeweils kürzere Drehrichtung nehmen (<180°)...

Meine Versuche in diese Richtung (siehe auskommentierte Zeilen in Klasse "SmallBoat", Funktion "update" Zeile 199+200) führen entweder dazu dass das kleine Schiff rückwärts fährt anstatt vorwärts oder dass es sich manchmal endlos dreht.

Das grosse "Ding" in der Mitte wird einmal ein Schlachtschiff, derzeit dreht es sich nur der Maus nach und hat mit meinem Problem nichts zu tun.

Programm benötigt pygame>1.8.1 und python>2.5

Code: Alles auswählen

# -*- coding: utf-8 -*-
"""
test für schlachtschiff. soll sich drehen, langsam in richtung Mauszeiger fahren,
kanone soll auf Sprite oder auf Mauszeiger zeigen.
Dieses Programm dient zur Problemlösung für das Spiel "Schiff",
zu finden unter
http://www.spielend-programmieren.at/wiki/doku.php?id=en:pygamebook:schiff
Lizenz: GPL
braucht: python 2.5 oder besser, pygame 1.8.1 oder besser
"""
import os
import pygame
import random
import math

# todo: pirat dreht manchmal in die falsche richtung. > 180 check ?
# ---------------------------

os.environ["SDL_VIDEO_CENTERED"] = "1" # center pygame window on screen
pygame.init()
screen=pygame.display.set_mode((640,480))
pygame.display.set_caption("press Esc to exit")

background = pygame.Surface(screen.get_size())
background = background.convert()
background.fill((255,255,255))     #fill the background white

xlist = range(0,screen.get_width(), 20)
ylist = range(0,screen.get_height(),20)
for x in xlist:
    if x%100 == 0: 
        color = (0,0,64)
    else:
        color = (64,64,255)
    pygame.draw.line(background, color, (x,0), (x,screen.get_height())) #light blue
for y in ylist:
    if y%100 == 0: 
        color = (0,0,64)
    else:
        color = (64,64,255)
    pygame.draw.line(background, color, (0, y), (screen.get_width(), y)) # dark blue
screen.blit(background, (0,0)) # blit the  backgroundsurface on the screen


class BigBoat(pygame.sprite.Sprite):
    """a big battleship"""
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        #self.image_orig = pygame.image.load("pygame_tiny.gif").convert_alpha()
        self.image = pygame.Surface((100,100)) # 
        self.image.fill((255,255,255)) # fill white
        pygame.draw.rect(self.image, (64,64,63), (0,0,100,100)) # rectangle
        pygame.draw.circle(self.image, (128,128,128), (50,25), 25) # north guntower
        pygame.draw.circle(self.image, (128,128,128), (50,75), 25) # south guntower
        pygame.draw.rect(self.image, (0,0,0), [25,0,50,5]) # north tip of boat
        self.image.set_colorkey((255,255,255)) # make white transparent
        self.image0 = self.image.copy()
        self.rect = self.image.get_rect()
        self.rect.center = (300,300)
        self.oldcenter = self.rect.center
        self.destination = pygame.mouse.get_pos()
        self.facing = 0
        self.oldfacing = 0
        self.enemy = (0,0)

    def learn(self,position):
        #self.enemy = position
        self.enemy = pygame.mouse.get_pos()

    def update(self, seconds_passed):
        self.oldfacing = self.facing #save old value
        pressed_keys = pygame.key.get_pressed()
        #if pressed_keys[pygame.K_a]:
        #    self.facing += 1
        #elif pressed_keys[pygame.K_d]:
        #    self.facing -=1

        #----rotation:
        # tan(alpha) = y/x
        # alpha = atan(y/x) # in radiant
        # alpha = atan(y/x) / (math.pi*2) * 360 # alpha in Grad      
        
        #---- where is the enemy, where am i ?
        dx =  self.enemy[0] - self.rect.centerx * 1.0 #float
        dy =  self.enemy[1] - self.rect.centery * 1.0
        try:
            # catch possible division by zero or invalid atan    
            winkel = math.atan(abs(dy/dx)) / (math.pi*2) * 360 # in Grad
            if (dx >= 0) and (dy >= 0):
                #quadrant = 1 # lower right
                self.facing = -winkel -90
            elif (dx < 0) and (dy >=0):
                #quadrant = 2  # lower left
                self.facing = winkel + 90
            elif (dx >=0) and (dy < 0):
                #quadrant = 3 # upper right
                self.facing = winkel -90
            elif (dx <0) and (dy < 0):
                #quadrant = 4
                self.facing = - winkel +90
            
        except:
            pass # division by zero ?
            
        #print dx, dy, self.facing
        
        if self.oldfacing != self.facing:
            self.oldcenter = self.rect.center
            self.image = pygame.transform.rotate(self.image0, self.facing)
            self.rect = self.image.get_rect()
            self.rect.center = self.oldcenter
         
        

class Cross(pygame.sprite.Sprite):
    """ a green cross indicating the destination of a boat """
    def __init__(self, boss):
        pygame.sprite.Sprite.__init__(self)
        self.boss = boss # the sprite i belong to
        self.image = pygame.Surface((10,10))
        self.image.fill((0,0,0)) #fill black
        pygame.draw.line(self.image, (0,255,0), (0,0), (10,10),4)
        pygame.draw.line(self.image, (0,255,0), (10,0), (0,10),4)
        self.image.set_colorkey((0,0,0)) # make black transparent
        self.image.convert_alpha() # necessary ?
        self.rect = self.image.get_rect()
        self.status = True
        
    def update(self, seconds_passed):
        #ignore seconds_passed
        self.rect.center = self.boss.destination

class SmallBoat(pygame.sprite.Sprite):
    """a small independent moving Baby Tux"""
    def __init__(self):
        "a small boat that drives around"
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((40,40))
        self.image.fill((255,255,255)) # fill white
        pygame.draw.polygon(self.image, (0,0,0), [(20,0), (40,40), (20, 20), (0,40)], 3)
        self.image.set_colorkey((255,255,255)) # make white tranparent
        self.image.convert_alpha() # to make sure tranparency works
        self.image0 = self.image.copy() # copy original image for rotation
        self.rect = self.image.get_rect()
        # TrueX,Y (float) because we want to be able to travel with less than 1 pixel /frame (very, very slow)
        self.TrueX =  0.0
        self.TrueY =  0.0
        self.rect.center = (0,0)
        self.oldcenter  = (0,0)
        self.facing = 0
        self.oldfacing = 0
        self.rotspeed = 90 # one half revolution per second
        self.newfacing = 0
        self.newDestination() #must be last line of init
        
    
    def newDestination(self):
        "calculate a random new Destination to travel and a random speed"
        self.destination = (random.randint(0,screen.get_width()), random.randint(0,screen.get_height()))
        self.speed = random.random() * 3 + 1.0
        #---calculate the way
        self.speedx = (self.destination[0] - self.rect.centerx ) / self.speed
        self.speedy = (self.destination[1] - self.rect.centery ) / self.speed
        #----rotation:
        #--calculate correct facing
        #---- where is the my destination, where am i ?
        dx =  self.destination[0] - self.rect.centerx * 1.0 #float
        dy =  self.destination[1] - self.rect.centery * 1.0
        try:   
            winkel = math.atan(abs(dy/dx)) / (math.pi*2) * 360 # in Grad
            if (dx >= 0) and (dy >= 0):
                self.newfacing = -winkel -90  #quadrant = 1 # lower right
            elif (dx < 0) and (dy >=0):
                self.newfacing = winkel + 90  #quadrant = 2  # lower left
            elif (dx >=0) and (dy < 0):
                self.newfacing = winkel -90   #quadrant = 3 # upper right
            elif (dx <0) and (dy < 0):
                self.newfacing = -winkel +90  #quadrant = 4 # upper left
            #print winkel, self.facing
        except:
            pass    # catch possible division by zero or invalid atan 
        
    def update(self, seconds_passed):
  
        #save old rotate value---------------------
        self.oldfacing = self.facing # save old facing value
        #---rotate of move ? ---
        face_diff = self.newfacing - self.facing
        #if face_diff < -180:
        #    face_diff = - 180 - face_diff
        #elif face_diff > 180:
        #    face_diff = 180 - face_diff
            
        #print face_diff
        if abs(face_diff) < 5: 
            #move ------------
            self.TrueX += self.speedx  * seconds_passed
            self.TrueY += self.speedy  * seconds_passed
        else:
            #rotate-----
            rot_dir = cmp(self.newfacing, self.facing) # return 0,-1 or 1
            #if abs(face_diff) > 180:
            #    rot_dir *= -1
            print self.facing, self.newfacing, face_diff
            self.facing += self.rotspeed * rot_dir * seconds_passed 
            
        #bounce --------------
        if self.TrueX > screen.get_width():
            self.TrueX = screen.get_width()
            self.newDestination()
        if self.TrueX < 0:
            self.TrueX = 0
            self.newDestination()
        if self.TrueY > screen.get_height():
            self.TrueY = screen.get_height()
            self.newDestination()
        if self.TrueY < 0:
            self.TrueY = 0
            self.newDestination()
        # calculate new position
        self.rect.centerx = round(self.TrueX,0) # make integer out of float
        self.rect.centery = round(self.TrueY,0)
        # destination reached ?
        # this is never exact, so give a tolerance of 5 pixel
        ##print self.rect.center, self.destination
        if abs(self.rect.centerx - self.destination[0]) < 5:
            if abs(self.rect.centery - self.destination[1]) < 5:
                 #print "i reached my goal"
                 self.newDestination()
        #rotate---------------
        if self.oldfacing != self.facing:
            self.oldcenter = self.rect.center
            self.image = pygame.transform.rotate(self.image0, self.facing)
            self.rect = self.image.get_rect()
            self.rect.center = self.oldcenter

#adding sprites to the game ------------------------

bigships = pygame.sprite.Group()
smallships = pygame.sprite.Group()
helper = pygame.sprite.Group() # a group for visual helpers like destination cross
royal1 = BigBoat() # the boat is so big, it get an individual name
bigships.add(royal1) # maybe it will some day get a sister ship, so it belongs to a group
pirate1 =  SmallBoat()
smallships.add(pirate1) ####small pirate boat(s); could also generate them inside group whithout name
for ship in smallships:
    helper.add(Cross(pirate1))
allsprites = pygame.sprite.LayeredUpdates(bigships, smallships, helper) # oder of drawing (groups)

#--- loop prepare ---
mainloop = True
fps = 30 #frames per second
seconds_played = 0.0

#--- mainloop ------
while mainloop:
    tick_time = pygame.time.Clock().tick(fps) # milliseconds since last frame
    seconds_passed = tick_time / 1000.0 # decimal-seconds since last frame
    seconds_played += seconds_passed # counter, will not be resetted    

    #event handler
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            mainloop = False
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE or event.key == pygame.K_q:
                mainloop = False

    # decorate pygame window
    pygame.display.set_caption("press [Esc] to quit. Facing:%i" % royal1.facing)

    allsprites.clear(screen, background)
    allsprites.update(seconds_passed)
    royal1.learn(pirate1.rect.center)
    allsprites.draw(screen)
    pygame.display.flip()

#--end of loop
pygame.quit() #idle-friendly quit



[/code]
https://spielend-programmieren.at
Antworten