Rotating character and sprite wall
<p>I have a sprite that represents my character. This sprite rotates every frame according to my mouse position which in turn makes it so my rectangle gets bigger and smaller depending on where the mouse is.   </p>

<p>Basically what I want is to make it so my sprite (<code>Character</code>) doesn't go into the sprite walls. Now since the rect for the walls are larger then the actual pictures seems and my rect keeps growing and shrinking depending on my mouse position it leaves me clueless as for how to make a statement that stops my sprite from moving into the walls in a convincing manner.</p>

<p>I already know for sure that my ColideList is only the blocks that are supposed to be collided with. I found <a href="http://stackoverflow.com/questions/20927189/detecting-collision-of-two-sprites-that-can-rotate">Detecting collision of two sprites that can rotate</a>, but it's in Java and I don't need to check collision between two rotating sprites but one and a wall.</p>

<p>My Character class looks like this:</p>

<pre><code>class Character(pygame.sprite.Sprite):
    walking_frame = []
    Max_Hp = 100
    Current_HP = 100
    Alive = True
    X_Speed = 0
    Y_Speed = 0
    Loc_x = 370
    Loc_y = 430
    size = 15
    Current_Weapon = Weapon()
    Angle = 0
    reloading = False
    shot = False
    LastFrame = 0
    TimeBetweenFrames = 0.05
    frame = 0
    Walking = False
    Blocked = 0
    rel_path = "Sprite Images/All.png"
    image_file = os.path.join(script_dir, rel_path)
    sprite_sheet = SpriteSheet(image_file) #temp
    image = sprite_sheet.get_image(0, 0, 48, 48) #Temp
    image = pygame.transform.scale(image, (60, 60))
    orgimage = image
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.walking_frame.append(self.image)
        image = self.sprite_sheet.get_image(48, 0, 48, 48)
        self.walking_frame.append(image)
        image = self.sprite_sheet.get_image(96, 0, 48, 48)
        self.walking_frame.append(image)
        image = self.sprite_sheet.get_image(144, 0, 48, 48)
        self.walking_frame.append(image)
        image = self.sprite_sheet.get_image(0, 48, 48, 48)
        self.walking_frame.append(image)
        image = self.sprite_sheet.get_image(48, 48, 48, 48)
        self.walking_frame.append(image)
        image = self.sprite_sheet.get_image(96, 48, 48, 48)
        self.walking_frame.append(image)
        image = self.sprite_sheet.get_image(144, 48, 48, 48)
        self.walking_frame.append(image)
        self.rect = self.image.get_rect()
        self.rect.left, self.rect.top = [self.Loc_x,self.Loc_y]
        print "Shabat Shalom"
    def Shoot(self):
        if self.Alive:
            if(self.reloading == False):
                if(self.Current_Weapon.Clip_Ammo &gt; 0):
                    bullet = Bullet(My_Man)
                    bullet_list.add(bullet)
                    self.Current_Weapon.Clip_Ammo -= 1
    def move(self):
        if self.Alive:
            self.Animation()

            self.Loc_x += self.X_Speed
            self.Loc_y += self.Y_Speed
            Wall_hit_List = pygame.sprite.spritecollide(My_Man, CollideList, False)
            self.Blocked = 0
            for wall in Wall_hit_List:
                if self.rect.right &lt;= wall.rect.left and self.rect.right &gt;= wall.rect.right:
                    self.Blocked = 1 #right
                    self.X_Speed= 0
                elif self.rect.left &lt;= wall.rect.right and self.rect.left &gt;= wall.rect.left:
                    self.Blocked = 3 #Left
                    self.X_Speed = 0
                elif self.rect.top &lt;= wall.rect.bottom and self.rect.top &gt;= wall.rect.top:
                    self.Blocked = 2 #Up
                    self.Y_Speed = 0
                elif self.rect.top &gt;= wall.rect.bottom and self.rect.top &lt;= wall.rect.top:
                    self.Blocked = 4 #Down
                    self.Y_Speed = 0
            self.image = pygame.transform.rotate(self.orgimage, self.Angle)
            self.rect = self.image.get_rect()
            self.rect.left, self.rect.top = [self.Loc_x, self.Loc_y]
    def Animation(self):
    #      #Character Walk Animation
        if self.X_Speed != 0 or self.Y_Speed != 0:
            if(self.Walking == False):
                self.LastFrame = time.clock()
                self.Walking = True
                if (self.frame &lt; len(self.walking_frame)):
                    self.image = self.walking_frame[self.frame]
                    self.image = pygame.transform.scale(self.image, (60, 60))
                    self.orgimage = self.image
                    self.frame += 1
                else:
                    self.frame = 0
        else:
            if self.frame != 0:
                self.frame = 0
                self.image = self.walking_frame[self.frame]
                self.image = pygame.transform.scale(self.image, (60, 60))
                self.orgimage = self.image
        if self.Walking and time.clock() - self.LastFrame &gt; self.TimeBetweenFrames:
            self.Walking = False
    def CalAngle(self,X,Y):
        angle = math.atan2(self.Loc_x - X, self.Loc_y - Y)
        self.Angle = math.degrees(angle) + 180
</code></pre>

<p>My Wall class looks like this:   </p>

<pre><code>class Wall(pygame.sprite.Sprite):
    def __init__(self, PosX, PosY, image_file, ImageX,ImageY):
        pygame.sprite.Sprite.__init__(self)
        self.sprite_sheet = SpriteSheet(image_file)
        self.image = self.sprite_sheet.get_image(ImageX, ImageY, 64, 64)
        self.image = pygame.transform.scale(self.image, (32, 32))
        self.image.set_colorkey(Black)
        self.rect = self.image.get_rect()
        self.rect.x = PosX
        self.rect.y = PosY
</code></pre>

<p>My BuildWall function looks like this: </p>

<pre><code>def BuildWall(NumberOfBlocks,TypeBlock,Direction,X,Y,Collide):
    for i in range(NumberOfBlocks):
        if Direction == 1:
            wall = Wall(X + (i * 32), Y, spriteList, 0, TypeBlock)
            wall_list.add(wall)
        if Direction == 2:
            wall = Wall(X - (i * 32), Y, spriteList, 0, TypeBlock)
            wall_list.add(wall)
        if Direction == 3:
            wall = Wall(X, Y + (i * 32), spriteList, 0, TypeBlock)
            wall_list.add(wall)
        if Direction == 4:
            wall = Wall(X, Y - (i * 32), spriteList, 0, TypeBlock)
            wall_list.add(wall)
        if(Collide):
            CollideList.add(wall)
</code></pre>

<p>Lastly my walking events looks like this:  </p>

<pre><code>elif event.type == pygame.KEYDOWN:
        if event.key == pygame.K_ESCAPE: #Press escape also leaves game
            Game = False
        elif event.key == pygame.K_w and My_Man.Blocked != 2:
            My_Man.Y_Speed = -3
        elif event.key == pygame.K_s and My_Man.Blocked != 4:
            My_Man.Y_Speed = 3
        elif event.key == pygame.K_a and My_Man.Blocked != 3:
            My_Man.X_Speed = -3
        elif event.key == pygame.K_d and My_Man.Blocked != 1:
            My_Man.X_Speed = 3
        elif event.key == pygame.K_r and (My_Man.reloading == False):
            lastReloadTime = time.clock()
            My_Man.reloading = True
            if (My_Man.Current_Weapon.Name == "Pistol"):
                My_Man.Current_Weapon.Clip_Ammo = My_Man.Current_Weapon.Max_Clip_Ammo
            else:
                My_Man.Current_Weapon.Clip_Ammo, My_Man.Current_Weapon.Max_Ammo = Reload(My_Man.Current_Weapon.Max_Ammo,My_Man.Current_Weapon.Clip_Ammo,My_Man.Current_Weapon.Max_Clip_Ammo)
    elif event.type == pygame.KEYUP:
        if event.key == pygame.K_w:
            My_Man.Y_Speed = 0
        elif event.key == pygame.K_s:
            My_Man.Y_Speed = 0
        elif event.key == pygame.K_a:
            My_Man.X_Speed = 0
        elif event.key == pygame.K_d:
            My_Man.X_Speed = 0
</code></pre>

<p>It all depends on how your sprite looks and how you want the result to be. There are 3 different types of collision detection I believe could work in your scenario.</p>

<h2>Keeping your rect from resizing</h2>

<p>Since the image is getting larger when you rotate it, you could compensate by just removing the extra padding and keep the image in it's original size. </p>

<p>Say that the size of the original image is 32 pixels wide and 32 pixels high. After rotating, the image is 36 pixels wide and 36 pixels high. We want to take out the center of the image (since the padding is added around it). </p>

<p><a href="http://i.stack.imgur.com/s0BQA.png" rel="nofollow"><img src="http://i.stack.imgur.com/s0BQA.png" alt="Ted Klein Bergman"></a></p>

<p>To take out the center of the new image we simply take out a subsurface of the image the size of our previous rectangle centered inside the image.</p>

<pre><code>def rotate(self, degrees):
    self.rotation = (self.rotation + degrees) % 360  # Keep track of the current rotation.
    self.image = pygame.transform.rotate(self.original_image, self.rotation))

    center_x = self.image.get_width() // 2
    center_y = self.image.get_height() // 2
    rect_surface = self.rect.copy()  # Create a new rectangle.
    rect_surface.center = (center_x, center_y)  # Move the new rectangle to the center of the new image.
    self.image = self.image.subsurface(rect_surface)  # Take out the center of the new image.
</code></pre>

<p>Since the size of the rectangle doesn't change we don't need to do anything to recalculate it (in other words: <code>self.rect = self.image.get_rect()</code> will not be necessary).</p>

<h2>Rectangular detection</h2>

<p>From here you just use <code>pygame.sprite.spritecollide</code> (or if you have an own function) as usual.</p>

<pre><code>def collision_rect(self, walls):
    last = self.rect.copy()  # Keep track on where you are.
    self.rect.move_ip(*self.velocity)  # Move based on the objects velocity.
    current = self.rect  # Just for readability we 'rename' the objects rect attribute to 'current'.
    for wall in pygame.sprite.spritecollide(self, walls, dokill=False):
        wall = wall.rect  # Just for readability we 'rename' the wall's rect attribute to just 'wall'.
        if last.left &gt;= wall.right &gt; current.left:  # Collided left side.
            current.left = wall.right
        elif last.right &lt;= wall.left &lt; current.right:  # Collided right side.
            current.right = wall.left
        elif last.top &gt;= wall.bottom &gt; current.top:  # Collided from above.
            current.top = wall.bottom
        elif last.bottom &lt;= wall.top &lt; current.bottom:  # Collided from below.
            current.bottom = wall.top
</code></pre>

<h2>Circular collision</h2>

<p>This probably will not work the best if you're tiling your walls, because you'll be able to go between tiles depending on the size of the walls and your character. It is good for many other things so I'll keep this in. </p>

<p>If you add the attribute <code>radius</code> to your player and wall you can use <code>pygame.sprite.spritecollide</code> and pass the callback function <code>pygame.sprite.collide_circle</code>. You don't need a radius attribute, it's optional. But if you don't pygame will calculate the radius based on the sprites rect attribute, which is unnecessary unless the radius is constantly changing.</p>

<pre><code>def collision_circular(self, walls):
    self.rect.move_ip(*self.velocity)
    current = self.rect
    for wall in pygame.sprite.spritecollide(self, walls, dokill=False, collided=pygame.sprite.collide_circle):
        distance = self.radius + wall.radius
        dx = current.centerx - wall.rect.centerx
        dy = current.centery - wall.rect.centery
        multiplier = ((distance ** 2) / (dx ** 2 + dy ** 2)) ** (1/2)
        current.centerx = wall.rect.centerx + (dx * multiplier)
        current.centery = wall.rect.centery + (dy * multiplier)
</code></pre>

<h2>Pixel perfect collision</h2>

<p>This is the hardest to implement and is performance heavy, but can give you the best result. We'll still use <code>pygame.sprite.spritecollide</code>, but this time we're going to pass <code>pygame.sprite.collide_mask</code> as the callback function. This method require that your sprites have a rect attribute and a per pixel alpha Surface or a Surface with a colorkey. You can read more on transparent Surfaces <a class='doc-link' href="http://stackoverflow.com/documentation/pygame/7079/drawing-on-the-screen/23788/transparency#t=201610011952123976046">here</a>. </p>

<p>A mask attribute is optional, if there is none the function will create one temporarily. If you use a mask attribute you'll need to change update it every time your sprite image is changed.</p>

<p>The hard part of this kind of collision is not to detect it but to respond correctly and make it move/stop appropriately. I made a buggy example demonstrating one way to handle it somewhat decently.</p>

<pre><code>def collision_mask(self, walls):
    last = self.rect.copy()
    self.rect.move_ip(*self.velocity)
    current = self.rect
    for wall in pygame.sprite.spritecollide(self, walls, dokill=False, collided=pygame.sprite.collide_mask):
        if not self.rect.center == last.center:
            self.rect.center = last.center
            break
        wall = wall.rect
        x_distance = current.centerx - wall.centerx
        y_distance = current.centery - wall.centery
        if abs(x_distance) &gt; abs(y_distance):
            current.centerx += (x_distance/abs(x_distance)) * (self.velocity[0] + 1)
        else:
            current.centery += (y_distance/abs(y_distance)) * (self.velocity[1] + 1)
</code></pre>

<h2>Full code</h2>

<p>You can try out the different examples by pressing 1 for rectangular collision, 2 for circular collision and 3 for pixel-perfect collision. It's a little buggy in some places, the movement isn't top notch and isn't ideal performance wise, but it's just a simple demonstration.</p>

<pre><code>import pygame
pygame.init()

SIZE = WIDTH, HEIGHT = (256, 256)
clock = pygame.time.Clock()
screen = pygame.display.set_mode(SIZE)
mode = 1
modes = ["Rectangular collision", "Circular collision", "Pixel perfect collision"]


class Player(pygame.sprite.Sprite):

    def __init__(self, pos):
        super(Player, self).__init__()
        self.original_image = pygame.Surface((32, 32))
        self.original_image.set_colorkey((0, 0, 0))
        self.image = self.original_image.copy()
        pygame.draw.ellipse(self.original_image, (255, 0, 0), pygame.Rect((0, 8), (32, 16)))

        self.rect = self.image.get_rect(center=pos)
        self.rotation = 0
        self.velocity = [0, 0]
        self.radius = self.rect.width // 2
        self.mask = pygame.mask.from_surface(self.image)

    def rotate_clipped(self, degrees):
        self.rotation = (self.rotation + degrees) % 360  # Keep track of the current rotation
        self.image = pygame.transform.rotate(self.original_image, self.rotation)

        center_x = self.image.get_width() // 2
        center_y = self.image.get_height() // 2
        rect_surface = self.rect.copy()  # Create a new rectangle.
        rect_surface.center = (center_x, center_y)  # Move the new rectangle to the center of the new image.
        self.image = self.image.subsurface(rect_surface)  # Take out the center of the new image.

        self.mask = pygame.mask.from_surface(self.image)

    def collision_rect(self, walls):
        last = self.rect.copy()  # Keep track on where you are.
        self.rect.move_ip(*self.velocity)  # Move based on the objects velocity.
        current = self.rect  # Just for readability we 'rename' the objects rect attribute to 'current'.
        for wall in pygame.sprite.spritecollide(self, walls, dokill=False):
            wall = wall.rect  # Just for readability we 'rename' the wall's rect attribute to just 'wall'.
            if last.left &gt;= wall.right &gt; current.left:  # Collided left side.
                current.left = wall.right
            elif last.right &lt;= wall.left &lt; current.right:  # Collided right side.
                current.right = wall.left
            elif last.top &gt;= wall.bottom &gt; current.top:  # Collided from above.
                current.top = wall.bottom
            elif last.bottom &lt;= wall.top &lt; current.bottom:  # Collided from below.
                current.bottom = wall.top

    def collision_circular(self, walls):
        self.rect.move_ip(*self.velocity)
        current = self.rect
        for wall in pygame.sprite.spritecollide(self, walls, dokill=False, collided=pygame.sprite.collide_circle):
            distance = self.radius + wall.radius
            dx = current.centerx - wall.rect.centerx
            dy = current.centery - wall.rect.centery
            multiplier = ((distance ** 2) / (dx ** 2 + dy ** 2)) ** (1/2)
            current.centerx = wall.rect.centerx + (dx * multiplier)
            current.centery = wall.rect.centery + (dy * multiplier)

    def collision_mask(self, walls):
        last = self.rect.copy()
        self.rect.move_ip(*self.velocity)
        current = self.rect
        for wall in pygame.sprite.spritecollide(self, walls, dokill=False, collided=pygame.sprite.collide_mask):
            if not self.rect.center == last.center:
                self.rect.center = last.center
                break
            wall = wall.rect
            x_distance = current.centerx - wall.centerx
            y_distance = current.centery - wall.centery
            if abs(x_distance) &gt; abs(y_distance):
                current.centerx += (x_distance/abs(x_distance)) * (self.velocity[0] + 1)
            else:
                current.centery += (y_distance/abs(y_distance)) * (self.velocity[1] + 1)

    def update(self, walls):
        self.rotate_clipped(1)

        if mode == 1:
            self.collision_rect(walls)
        elif mode == 2:
            self.collision_circular(walls)
        else:
            self.collision_mask(walls)


class Wall(pygame.sprite.Sprite):

    def __init__(self, pos):
        super(Wall, self).__init__()
        size = (32, 32)
        self.image = pygame.Surface(size)
        self.image.fill((0, 0, 255))  # Make the Surface blue.
        self.image.set_colorkey((0, 0, 0))  # Will not affect the image but is needed for collision with mask.
        self.rect = pygame.Rect(pos, size)

        self.radius = self.rect.width // 2
        self.mask = pygame.mask.from_surface(self.image)


def show_rects(player, walls):
    for wall in walls:
        pygame.draw.rect(screen, (1, 1, 1), wall.rect, 1)
    pygame.draw.rect(screen, (1, 1, 1), player.rect, 1)


def show_circles(player, walls):
    for wall in walls:
        pygame.draw.circle(screen, (1, 1, 1), wall.rect.center, wall.radius, 1)
    pygame.draw.circle(screen, (1, 1, 1), player.rect.center, player.radius, 1)


def show_mask(player, walls):
    for wall in walls:
        pygame.draw.rect(screen, (1, 1, 1), wall.rect, 1)
    for pixel in player.mask.outline():
        pixel_x = player.rect.x + pixel[0]
        pixel_y = player.rect.y + pixel[1]
        screen.set_at((pixel_x, pixel_y), (1, 1, 1))

# Create walls around the border.
walls = pygame.sprite.Group()
walls.add(Wall(pos=(col, 0)) for col in range(0, WIDTH, 32))
walls.add(Wall(pos=(0, row)) for row in range(0, HEIGHT, 32))
walls.add(Wall(pos=(col, HEIGHT - 32)) for col in range(0, WIDTH, 32))
walls.add(Wall(pos=(WIDTH - 32, row)) for row in range(0, HEIGHT, 32))
walls.add(Wall(pos=(WIDTH//2, HEIGHT//2)))  # Obstacle in the middle of the screen

player = Player(pos=(64, 64))
speed = 2  # Speed of the player.
while True:
    screen.fill((255, 255, 255))
    clock.tick(60)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            quit()
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_a:
                player.velocity[0] = -speed
            elif event.key == pygame.K_d:
                player.velocity[0] = speed
            elif event.key == pygame.K_w:
                player.velocity[1] = -speed
            elif event.key == pygame.K_s:
                player.velocity[1] = speed
            elif pygame.K_1 &lt;= event.key &lt;= pygame.K_3:
                mode = event.key - 48
                print(modes[mode - 1])
        elif event.type == pygame.KEYUP:
            if event.key == pygame.K_a or event.key == pygame.K_d:
                player.velocity[0] = 0
            elif event.key == pygame.K_w or event.key == pygame.K_s:
                player.velocity[1] = 0

    player.update(walls)
    walls.draw(screen)
    screen.blit(player.image, player.rect)

    if mode == 1:
        show_rects(player, walls)  # Show rectangles for circular collision detection.
    elif mode == 2:
        show_circles(player, walls)  # Show circles for circular collision detection.
    else:
        show_mask(player, walls)  # Show mask for pixel perfect collision detection.

    pygame.display.update()
</code></pre>

<h2>Last note</h2>

<p>Before programming any further you really need to refactor your code. I tried to read some of your code but it's really hard to understand. Try follow <a href="https://www.python.org/dev/peps/pep-0008/#prescriptive-naming-conventions" rel="nofollow">Python's naming conventions</a>, it'll make it much easier for other programmers to read and understand your code, which makes it easier for them to help you with your questions.</p>

<p>Just following these simple guidelines will make your code much readable:</p>

<ul>
<li>Variable names should contain only lowercase letters. Names with more than 1 word should be separated with an underscore. Example: <code>variable</code>, <code>variable_with_words</code>.</li>
<li>Functions and attributes should follow the same naming convention as variables.</li>
<li>Class names should start with an uppercase for every word and the rest should be lowercase. Example: <code>Class</code>, <code>MyClass</code>. Known as CamelCase.</li>
<li>Separate methods in classes with one line, and functions and classes with two lines.</li>
</ul>

<p>I don't know what kind of IDE you use, but <a href="https://www.jetbrains.com/pycharm/download/#section=windows" rel="nofollow">Pycharm Community Edition</a> is a great IDE for Python. It'll show you when you're breaking Python conventions (and much more of course).</p>

<p>It's important to note that these are conventions and not rules. They are meant to make code more readable and not to be followed strictly. Break them if you think it improves readability.</p>

python python-2.7 pygame sprite