dear masters of pygame, i'm stuck at a little problem but too tired to find a solution: want to rotate a little sprite (pirate1, class smallboat) in the correct way (minimal rotating time) either clockwise or counterclockwise. at the moment the sprite rotate itself half the time in the wrong direction. sprite rotate until it can mofe forward to the green cross. i tryed to calculate the amount of degrees (Grad) to rotate and decide to flip rotation direction if amount > 180; (line 202 and 203, out-commented) but somehow my sprite then goes either backwards instead forward or is stuck in a never ending rotating loop. the version attached rotate the sprite half the time in the wrong direction. (ignore the big sprite in the middle). program need pygame>1.8.1 and python>2.5 nearly all comments in English, only docstring and todo in German greetings & many thanks in advance for any hint, -Horst -- Horst JENS horst.jens@xxxxxxxxx http://members.chello.at/horst.jens
# -*- coding: utf-8 -*- """ test für schlachtschiff. soll sich drehen, langsam in richtung Mauszeiger fahren, kanone soll auf Sprite oder auf Mauszeiger zeigen. """ import os import pygame import random import math # todo: pirat dreht manchmal in die falsche richtung. > 180 check ? # todo: pirat "zittert" manchmal lange ... rotspeed senken ? toleranz erhöhen ? # --------------------------- 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 #from file: #background = pygame.image.load("horst.jpg") #or create on the fly: background = pygame.Surface(screen.get_size()) background = background.convert() background.fill((255,255,255)) #fill the background white # make a more pretty background: #blue line each 20 pixel # black line each 100 pixel 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): #quadrant = 1 # lower right self.newfacing = -winkel -90 elif (dx < 0) and (dy >=0): #quadrant = 2 # lower left self.newfacing = winkel + 90 elif (dx >=0) and (dy < 0): #quadrant = 3 # upper right self.newfacing = winkel -90 elif (dx <0) and (dy < 0): #quadrant = 4 self.newfacing = -winkel +90 #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 ? --- #--- this is not exact, so give a tolerance #if self.facing > 180: #self.facing = 180 - self.facing #if self.facing < -180: #self.facing = -180 - self.facing #if self.newfacing > 180: #self.newfacing = 180 - self.facing #if self.newfacing < -180: #self.newfacing = -180 - self.facing # move or rotate ?----------- 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); not important enough to get a individual name for ship in smallships: helper.add(Cross(pirate1)) allsprites = pygame.sprite.LayeredUpdates(bigships, smallships, helper) # oder of drawing (groups) # variables needed for snake #showBorder = False #a bit of text #myFont = pygame.font.SysFont("None",20) #textsurface = myFont.render("press b or n to toggle border rect/ color", True, (0,0,255)) #textsurface2 = myFont.render("press ESC or q to quit", True, (0,0,255)) #background.blit(textsurface, (100,screen.get_height()/2)) # blit the textsurface on the backgroundsurface #background.blit(textsurface2, (100, screen.get_height()/2+20)) #screen.blit(background, (0,0)) # blit the backgroundsurface on the screen #--- loop prepare --- mainloop = True #clock = pygame.time.Clock() 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 #change = False # any update #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 # more precise keyboard event handler #pressed_keys = pygame.key.get_pressed() #if pressed_keys[pygame.K_b]: #BigBoat collide with Pirate ? #crashGroup = pygame.sprite.spritecollide(Cobra, Babys, False) #for penguin in crashGroup: # penguin.neg = True #Babytux crash into Babytux ? #for penguin in babysprites: # othergroup = babysprites.copy() # othergroup.remove(penguin) # a copy of the group without the current penguin # if pygame.sprite.spritecollideany(penguin, othergroup): # penguin.neg = True # penguin.newspeed() # decorate pygame window pygame.display.set_caption("press [Esc] to quit. Facing:%i" % royal1.facing) allsprites.clear(screen, background) allsprites.update(seconds_passed) # royal1 has to learn the position of pirate1 royal1.learn(pirate1.rect.center) allsprites.draw(screen) #for everyone pygame.display.flip() #--end of loop pygame.quit() #idle-friendly quit
Attachment:
signature.asc
Description: Dies ist ein digital signierter Nachrichtenteil