I've been messing around with a sample from the L Line's book on game programming, and I've tried to further develop their space.py example that demonstrates a ship without friction. I've tried my hardest to properly enter collision detection on a set of 40,40 rects that are placed throughout the 800,600 screen, but it is proving to be a bit harder than first imagined. The issues that I am noticing is that sometimes the sprite will catch the collisions, sometimes they won't. Another is the rotate() method. If I rotated, the sprite's rect will expand and throw off the collision detection as well, sending the sprite all throughout the screen and eventually off into the great unknown. May I ask for assistance in pointing me to what I am doing wrong with this? I would greatly appreciate any help provided! Thank you very very much!
""" space.py simulate a spacecraft with no traction at all """ import pygame, math pygame.init() class Ship(pygame.sprite.Sprite): # Sprite containing the main ship that the user will control in the game. # Methods: # update() # checkKeys() # rotate() # calcVector() # setPos() # checkCollision() def __init__(self, screen, walls, map): pygame.sprite.Sprite.__init__(self) self.walls = walls #import the wall sprite group for collision detection self.imageThrust = pygame.image.load("shipThrust.png") #image for the sprite while applying thrust self.imageThrust = self.imageThrust.convert() self.imageCruise = pygame.image.load("shipCruise.png") #image for the sprite when idle self.imageCruise = self.imageCruise.convert() self.imageLeft = pygame.image.load("shipLeft.png") #image for the sprite when rotating left self.imageLeft = self.imageLeft.convert() self.imageRight = pygame.image.load("shipRight.png") #image for the sprite when rotating right self.imageRight = self.imageRight.convert() #designate the initial master image and get the rect for it self.imageMaster = self.imageCruise self.image = self.imageMaster self.rect = self.image.get_rect() #some initial properties, including initial position, difference in x/y, direction, turn rate, #and thrust of the Ship sprite self.x = 100 self.y = 100 self.dx = 0 self.dy = 0 self.dir = 0 self.turnRate = 5 self.thrust = 0 def update(self): #The default update method that is called in the main loop. #all further methods are properly encapsulated in order #to keep stuff tidy! self.checkKeys() self.rotate() self.calcVector() self.checkCollision() self.setPos() #after all the methods get their chance, we finish up this frame by #placing the sprite in the proper x and y position self.rect.center = (self.x, self.y) def checkKeys(self): #we store the pressed key in the variable "keys" so that we may flip through #all the posibilities. Note that we are doing individual if statements #so that we may apply multiple keys at once, instead of one at a time with #the elif approach keys = pygame.key.get_pressed() self.imageMaster = self.imageCruise #start with the cruising sprite image if keys[pygame.K_RIGHT]: self.dir -= self.turnRate #rotate clockwise if self.dir < 0: self.dir = 360 - self.turnRate self.imageMaster = self.imageRight self.checkCollision() if keys[pygame.K_LEFT]: self.dir += self.turnRate #rotate counter-clockwise if self.dir > 360: self.dir = self.turnRate self.imageMaster = self.imageLeft self.checkCollision() if keys[pygame.K_UP]: self.thrust = .1 #apply thrust self.imageMaster = self.imageThrust else: self.thrust = 0 #nothing was pressed, speed will remain constant def rotate(self): oldCenter = self.rect.center #get the old center so that we may recenter after rotating self.image = pygame.transform.rotate(self.imageMaster, self.dir) self.rect = self.image.get_rect() #get the rect for the newly rotated sprite self.rect.center = oldCenter #and center it back on it's old x,y coord's def calcVector(self): radians = self.dir * math.pi / 180 thrustDx = self.thrust * math.cos(radians) thrustDy = self.thrust * math.sin(radians) thrustDy *= -1 self.dx += thrustDx self.dy += thrustDy self.speed = math.sqrt((self.dx * self.dx) + (self.dy * self.dy)) def setPos(self): #The final piece before the x/y coords are placed on the sprite self.x += self.dx self.y += self.dy def checkCollision(self): # # !!BROKEN!! # # Currently I have this set to detect for each rect in the walls sprite group # If it collides with any of them, it will determine based off of the difference # in x/y to see what direction it collided from. Once it determines the direction, # it will clear the dx/dy (based on how it hit) so that the ship sprite will not # move once it goes to the setPos() method, and it will also move it so that it # is 15 pixels from the center of the direction it hit the wall. I chose 15px # in this hopes that it will move it 1px extra away from the wall. for wall in self.walls: if self.rect.colliderect(wall.rect): if self.dx > 0: self.dx = 0 self.x = wall.rect.left-15 if self.dx < 0: self.dx = 0 self.x = wall.rect.right+15 if self.dy > 0: self.dy = 0 self.y = wall.rect.top-15 if self.dy < 0: self.dy = 0 self.y = wall.rect.bottom+15 class Map(object): # Sprite containing the boundaries and walls def __init__(self,walls,screen): self.walls = walls self.screen = screen self.grid = [ "++++++++++++++++++++", "+ + +", "+ + +", "+ + +", "+ + +", "+ + +", "+ ++++++", "+ +", "++++++ +", "+ + +", "+ + +", "+ + +", "+ + +", "+ + +", "++++++++++++++++++++" ] self.x = self.y = 0 for row in self.grid: for col in row: if col == "+": self.walls.add(Walls(self.x, self.y, self.walls, self.screen)) self.x += 40 self.y += 40 self.x = 0 class Walls(pygame.sprite.Sprite): def __init__(self, x, y, walls, screen): pygame.sprite.Sprite.__init__(self) self.image = pygame.Surface((40,40)) self.image.fill((0,0,0)) self.rect = self.image.get_rect() self.rect.topleft = x,y def main(): screen = pygame.display.set_mode((800, 600)) pygame.display.set_caption("Space craft") background = pygame.Surface(screen.get_size()) background.fill((200, 200, 200)) screen.blit(background, (0, 0)) walls = pygame.sprite.Group() map = Map(walls, screen) ship = Ship(screen, walls, map) allSprites = pygame.sprite.Group(ship, walls) clock = pygame.time.Clock() keepGoing = True while keepGoing: clock.tick(50) for event in pygame.event.get(): if event.type == pygame.QUIT: keepGoing = False allSprites.clear(screen, background) allSprites.update() allSprites.draw(screen) pygame.display.flip() if __name__ == "__main__": main() of note, if anyone would like to test it, the images can be downloaded at these links: http://www.cs.iupui.edu/~aharris/pygame/ch09/shipCruise.png http://www.cs.iupui.edu/~aharris/pygame/ch09/shipLeft.png http://www.cs.iupui.edu/~aharris/pygame/ch09/shipRight.png http://www.cs.iupui.edu/~aharris/pygame/ch09/shipThrust.png Again, thank you very much for the help! Sincerely, Scotty Miller Email: miller.scot...@gmail.com Website: http://scottymiller.net Blackberry: 760-468-7899