Add collison detection to enemy sprites?

Posted by xBroak on Game Development See other posts from Game Development or by xBroak
Published on 2012-11-30T14:38:32Z Indexed on 2012/11/30 17:21 UTC
Read the original article Hit count: 648

Filed under:
|

i'd like to add the same collision detection used by the player sprite to the enemy sprites or 'creeps' ive added all the relevant code I can see yet collisons are still not being detected and handled, please find below the class, I have no idea what is wrong currently, the list of walls to collide with is 'wall_list'

import pygame
import pauseScreen as dm
import re
from pygame.sprite import Sprite
from pygame import Rect, Color
from random import randint, choice
from vec2d import vec2d
from simpleanimation import SimpleAnimation
import displattxt
black = (0,0,0)
white = (255,255,255)
blue = (0,0,255)
green = (101,194,151)
global currentEditTool
currentEditTool = "Tree"
global editMap


editMap = False
open('MapMaker.txt', 'w').close()
def draw_background(screen, tile_img):
        screen.fill(black)
        img_rect = tile_img.get_rect()
        global rect
        rect = img_rect

        nrows = int(screen.get_height() / img_rect.height) + 1
        ncols = int(screen.get_width() / img_rect.width) + 1

        for y in range(nrows):
            for x in range(ncols):
                img_rect.topleft = (x * img_rect.width,
                                    y * img_rect.height)
                screen.blit(tile_img, img_rect)

def changeTool():
        if currentEditTool == "Tree":
                None
        elif currentEditTool == "Rock":
                None

def pauseGame():
        red   = 255,  0,  0
        green =   0,255,  0
        blue  =   0,  0,255  
        screen.fill(black)
        pygame.display.update()
        if editMap == False:
                choose = dm.dumbmenu(screen, [
                                'Resume',
                                'Enable Map Editor',
                                'Quit Game'], 64,64,None,32,1.4,green,red)

                if choose == 0:
                        print("hi")
                elif choose ==1:
                        global editMap
                        editMap = True
                elif choose ==2:
                        print("bob")
                elif choose ==3:
                        print("bob")
                elif choose ==4:
                        print("bob")
                else:
                        None      
        else:
                choose = dm.dumbmenu(screen, [
                                'Resume',
                                'Disable Map Editor',
                                'Quit Game'], 64,64,None,32,1.4,green,red)

                if choose == 0:
                        print("Resume")
                elif choose ==1:
                        print("Dis ME")
                        global editMap
                        editMap = False
                elif choose ==2:
                        print("bob")
                elif choose ==3:
                        print("bob")
                elif choose ==4:
                        print("bob")
                else:
                        None                   

class Wall(pygame.sprite.Sprite):
    # Constructor function
    def __init__(self,x,y,width,height):
        pygame.sprite.Sprite.__init__(self)   
        self.image = pygame.Surface([width, height])
        self.image.fill(green)
        self.rect = self.image.get_rect()
        self.rect.y = y
        self.rect.x = x


class insertTree(pygame.sprite.Sprite):

    def __init__(self,x,y,width,height, typ):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load("images/map/tree.png").convert()
        self.image.set_colorkey(white)
        self.rect = self.image.get_rect()
        self.rect.y = y
        self.rect.x = x

class insertRock(pygame.sprite.Sprite):

    def __init__(self,x,y,width,height, typ):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load("images/map/rock.png").convert()
        self.image.set_colorkey(white)
        self.rect = self.image.get_rect()
        self.rect.y = y
        self.rect.x = x

class Creep(pygame.sprite.Sprite):
    """ A creep sprite that bounces off walls and changes its
        direction from time to time.
    """
    change_x=0
    change_y=0
    def __init__(   
            self, screen, creep_image, explosion_images, 
            field, init_position, init_direction, speed):
        """ Create a new Creep.

            screen: 
                The screen on which the creep lives (must be a 
                pygame Surface object, such as pygame.display)

            creep_image: 
                Image (surface) object for the creep

            explosion_images:
                A list of image objects for the explosion 
                animation.

            field:
                A Rect specifying the 'playing field' boundaries.
                The Creep will bounce off the 'walls' of this 
                field.

            init_position:
                A vec2d or a pair specifying the initial position
                of the creep on the screen.

            init_direction:
                A vec2d or a pair specifying the initial direction
                of the creep. Must have an angle that is a 
                multiple of 45 degres.

            speed: 
                Creep speed, in pixels/millisecond (px/ms)
        """
        Sprite.__init__(self)

        self.screen = screen
        self.speed = speed
        self.field = field
        self.rect = creep_image.get_rect()

        # base_image holds the original image, positioned to
        # angle 0.
        # image will be rotated.
        #
        self.base_image = creep_image
        self.image = self.base_image
        self.explosion_images = explosion_images

        # A vector specifying the creep's position on the screen
        #
        self.pos = vec2d(init_position)

        # The direction is a normalized vector
        #
        self.direction = vec2d(init_direction).normalized()

        self.state = Creep.ALIVE
        self.health = 15

    def is_alive(self):
        return self.state in (Creep.ALIVE, Creep.EXPLODING)

    def changespeed(self,x,y):
        self.change_x+=x
        self.change_y+=y

    def update(self, time_passed, walls):
        """ Update the creep.

            time_passed:
                The time passed (in ms) since the previous update.
        """
        if self.state == Creep.ALIVE:
            # Maybe it's time to change the direction ?
            #
            self._change_direction(time_passed)

            # Make the creep point in the correct direction.
            # Since our direction vector is in screen coordinates 
            # (i.e. right bottom is 1, 1), and rotate() rotates 
            # counter-clockwise, the angle must be inverted to 
            # work correctly.
            #
            self.image = pygame.transform.rotate(
                self.base_image, -self.direction.angle)

            # Compute and apply the displacement to the position 
            # vector. The displacement is a vector, having the angle
            # of self.direction (which is normalized to not affect
            # the magnitude of the displacement)
            #
            displacement = vec2d(    
                self.direction.x * self.speed * time_passed,
                self.direction.y * self.speed * time_passed)

            self.pos += displacement

            # When the image is rotated, its size is changed.
            # We must take the size into account for detecting 
            # collisions with the walls.
            #
            self.image_w, self.image_h = self.image.get_size()
            bounds_rect = self.field.inflate(
                            -self.image_w, -self.image_h)

            if self.pos.x < bounds_rect.left:
                self.pos.x = bounds_rect.left
                self.direction.x *= -1
            elif self.pos.x > bounds_rect.right:
                self.pos.x = bounds_rect.right
                self.direction.x *= -1
            elif self.pos.y < bounds_rect.top:
                self.pos.y = bounds_rect.top
                self.direction.y *= -1
            elif self.pos.y > bounds_rect.bottom:
                self.pos.y = bounds_rect.bottom
                self.direction.y *= -1

        # collision detection
        old_x=bounds_rect.left
        new_x=old_x+self.direction.x
        bounds_rect.left = new_x

        # hit a wall?
        collide = pygame.sprite.spritecollide(self, walls, False)
        if collide:
            # yes
            bounds_rect.left=old_x

        old_y=self.pos.y
        new_y=old_y+self.direction.y
        self.pos.y = new_y

        collide = pygame.sprite.spritecollide(self, walls, False)
        if collide:
            # yes
            self.pos.y=old_y

        elif self.state == Creep.EXPLODING:
            if self.explode_animation.active:
                self.explode_animation.update(time_passed)
            else:
                self.state = Creep.DEAD
                self.kill()

        elif self.state == Creep.DEAD:
            pass

        #------------------ PRIVATE PARTS ------------------#

    # States the creep can be in.
    #
    # ALIVE: The creep is roaming around the screen
    # EXPLODING: 
    #   The creep is now exploding, just a moment before dying.
    # DEAD: The creep is dead and inactive
    #
    (ALIVE, EXPLODING, DEAD) = range(3)

    _counter = 0

    def _change_direction(self, time_passed):
        """ Turn by 45 degrees in a random direction once per
            0.4 to 0.5 seconds.
        """
        self._counter += time_passed
        if self._counter > randint(400, 500):
            self.direction.rotate(45 * randint(-1, 1))
            self._counter = 0

    def _point_is_inside(self, point):
        """ Is the point (given as a vec2d) inside our creep's
            body?
        """
        img_point = point - vec2d(  
            int(self.pos.x - self.image_w / 2),
            int(self.pos.y - self.image_h / 2))

        try:
            pix = self.image.get_at(img_point)
            return pix[3] > 0
        except IndexError:
            return False

    def _decrease_health(self, n):
        """ Decrease my health by n (or to 0, if it's currently
            less than n)
        """
        self.health = max(0, self.health - n)
        if self.health == 0:
            self._explode()




    def _explode(self):
        """ Starts the explosion animation that ends the Creep's
            life.
        """
        self.state = Creep.EXPLODING
        pos = ( self.pos.x - self.explosion_images[0].get_width() / 2,
                self.pos.y - self.explosion_images[0].get_height() / 2)
        self.explode_animation = SimpleAnimation(
            self.screen, pos, self.explosion_images,
            100, 300)
        global remainingCreeps

        remainingCreeps-=1

        if remainingCreeps == 0:
                print("all dead")

    def draw(self):
        """ Blit the creep onto the screen that was provided in
            the constructor.
        """
        if self.state == Creep.ALIVE:
            # The creep image is placed at self.pos. To allow for 
            # smooth movement even when the creep rotates and the 
            # image size changes, its placement is always 
            # centered.
            #
            self.draw_rect = self.image.get_rect().move(
                self.pos.x - self.image_w / 2, 
                self.pos.y - self.image_h / 2)
            self.screen.blit(self.image, self.draw_rect)

            # The health bar is 15x4 px.
            #
            health_bar_x = self.pos.x - 7
            health_bar_y = self.pos.y - self.image_h / 2 - 6
            self.screen.fill(   Color('red'), 
                                (health_bar_x, health_bar_y, 15, 4))
            self.screen.fill(   Color('green'), 
                                (   health_bar_x, health_bar_y, 
                                    self.health, 4))

        elif self.state == Creep.EXPLODING:
            self.explode_animation.draw()

        elif self.state == Creep.DEAD:
            pass

    def mouse_click_event(self, pos):
        """ The mouse was clicked in pos.
        """
        if self._point_is_inside(vec2d(pos)):
            self._decrease_health(3)
#begin new player

class Player(pygame.sprite.Sprite):

    change_x=0
    change_y=0
    frame = 0

    def __init__(self,x,y):

        pygame.sprite.Sprite.__init__(self)
        # LOAD PLATER IMAGES
        # Set height, width
        self.images = []
        for i in range(1,17):
            img = pygame.image.load("images/player/" + str(i)+".png").convert() #player images
            img.set_colorkey(white)
            self.images.append(img)
        self.image = self.images[0]
        self.rect = self.image.get_rect()
        self.rect.y = y
        self.rect.x = x
        self.health = 15
        self.image_w, self.image_h = self.image.get_size()
        health_bar_x = self.rect.x - 7
        health_bar_y = self.rect.y - self.image_h / 2 - 6
        screen.fill(   Color('red'), 
                                (health_bar_x, health_bar_y, 15, 4))
        screen.fill(   Color('green'), 
                                (   health_bar_x, health_bar_y, 
                                    self.health, 4))

    def changespeed(self,x,y):
        self.change_x+=x
        self.change_y+=y

    def _decrease_health(self, n):
        """ Decrease my health by n (or to 0, if it's currently
            less than n)
        """
        self.health = max(0, self.health - n)
        if self.health == 0:
            self._explode()

    def update(self,walls):
        # collision detection
        old_x=self.rect.x
        new_x=old_x+self.change_x
        self.rect.x = new_x

        # hit a wall?
        collide = pygame.sprite.spritecollide(self, walls, False)
        if collide:
            # yes
            self.rect.x=old_x

        old_y=self.rect.y
        new_y=old_y+self.change_y
        self.rect.y = new_y

        collide = pygame.sprite.spritecollide(self, walls, False)
        if collide:
            # yes
            self.rect.y=old_y


        # right to left
        if self.change_x < 0:
            self.frame += 1
            if self.frame > 3*4:
                self.frame = 0                 
            # Grab the image, divide by 4
            # every 4 frames. 
            self.image = self.images[self.frame//4]

        # Move left to right.
        # images 4...7 instead of 0...3.
        if self.change_x > 0:
            self.frame += 1
            if self.frame > 3*4:
                self.frame = 0
            self.image = self.images[self.frame//4+4]

        if self.change_y > 0:
            self.frame += 1
            if self.frame > 3*4:
                self.frame = 0
            self.image = self.images[self.frame//4+4+4]

        if self.change_y < 0:
            self.frame += 1
            if self.frame > 3*4:
                self.frame = 0
            self.image = self.images[self.frame//4+4+4+4]


score = 0
# initialize pyGame
pygame.init()

# 800x600 sized screen
global screen
screen = pygame.display.set_mode([800, 600])
screen.fill(black)
#bg_tile_img = pygame.image.load('images/map/grass.png').convert_alpha()
#draw_background(screen, bg_tile_img)
#pygame.display.flip()
# Set title
pygame.display.set_caption('Test')

#background = pygame.Surface(screen.get_size())
#background = background.convert()
#background.fill(black)

# Create the player
player = Player( 50,50 )
player.rect.x=50
player.rect.y=50
movingsprites = pygame.sprite.RenderPlain()
movingsprites.add(player)

# Make the walls. (x_pos, y_pos, width, height)
global wall_list
wall_list=pygame.sprite.RenderPlain()
wall=Wall(0,0,10,600) # left wall
wall_list.add(wall)
wall=Wall(10,0,790,10) # top wall
wall_list.add(wall)
#wall=Wall(10,200,100,10) # poke wall 
wall_list.add(wall)
wall=Wall(790,0,10,600) #(x,y,thickness, height)
wall_list.add(wall)
wall=Wall(10,590,790,10)  #(x,y,thickness, height)
wall_list.add(wall)


f = open('MapMaker.txt')
num_lines = sum(1 for line in f)
print(num_lines)
lineCount = 0
with open("MapMaker.txt") as infile:
    for line in infile:
       f = open('MapMaker.txt')
       print(line)

       coords = line.split(',')
       #print(coords[0])
       #print(coords[1])
       #print(coords[2])
       #print(coords[3])
       #print(coords[4])
       if "tree" in line:
          print("tree in")
          wall=insertTree(int(coords[0]),int(coords[1]), int(coords[2]),int(coords[3]),coords[4])
          wall_list.add(wall)
       elif "rock" in line:
          print("rock in")
          wall=insertRock(int(coords[0]),int(coords[1]), int(coords[2]),int(coords[3]),coords[4] )
          wall_list.add(wall)






width = 20
height = 540
height = height - 48
for i in range(0,23):
    width = width + 32
    name = insertTree(width,540,790,10,"tree")
    #wall_list.add(name)
    name = insertTree(width,height,690,10,"tree")
    #wall_list.add(name)


CREEP_SPAWN_TIME = 200 # frames

creep_spawn = CREEP_SPAWN_TIME

clock = pygame.time.Clock()
bg_tile_img = pygame.image.load('images/map/grass.png').convert()
img_rect = bg_tile_img
FIELD_RECT = Rect(50, 50, 700, 500)
CREEP_FILENAMES = [
     'images/player/1.png', 
    'images/player/1.png', 
    'images/player/1.png']
N_CREEPS = 3

creep_images = [
    pygame.image.load(filename).convert_alpha() 
    for filename in CREEP_FILENAMES]
explosion_img = pygame.image.load('images/map/tree.png').convert_alpha()
explosion_images = [
    explosion_img, pygame.transform.rotate(explosion_img, 90)]

creeps = pygame.sprite.RenderPlain()


done = False
#bg_tile_img = pygame.image.load('images/map/grass.png').convert()
#draw_background(screen, bg_tile_img)

totalCreeps = 0
remainingCreeps = 3
while done == False:

    creep_images = pygame.image.load("images/player/1.png").convert()
    creep_images.set_colorkey(white)
    draw_background(screen, bg_tile_img)

    if len(creeps) != N_CREEPS:

        if totalCreeps < N_CREEPS:
                        totalCreeps = totalCreeps + 1
                        print(totalCreeps)
                        creeps.add(
                        Creep(  screen=screen,
                        creep_image=creep_images, 
                        explosion_images=explosion_images,
                        field=FIELD_RECT,
                        init_position=( randint(FIELD_RECT.left, 
                                                FIELD_RECT.right), 
                                        randint(FIELD_RECT.top, 
                                                FIELD_RECT.bottom)), 
                        init_direction=(choice([-1, 1]), 
                                        choice([-1, 1])),
                        speed=0.01))

    for creep in creeps:

                    creep.update(60,wall_list)
                    creep.draw()



    for event in pygame.event.get():


        if event.type == pygame.QUIT:
            done=True

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                player.changespeed(-2,0)
                creep.changespeed(-2,0)
            if event.key == pygame.K_RIGHT:
                player.changespeed(2,0)
                creep.changespeed(2,0)
            if event.key == pygame.K_UP:
                player.changespeed(0,-2)
                creep.changespeed(0,-2)
            if event.key == pygame.K_DOWN:
                player.changespeed(0,2)
                creep.changespeed(0,2)
            if event.key == pygame.K_ESCAPE:
                pauseGame()
            if event.key == pygame.K_1:
                global currentEditTool
                currentEditTool = "Tree"
                changeTool()
            if event.key == pygame.K_2:
                global currentEditTool
                currentEditTool = "Rock"
                changeTool()

        if event.type == pygame.KEYUP:
            if event.key == pygame.K_LEFT:
                player.changespeed(2,0)
                creep.changespeed(2,0)
            if event.key == pygame.K_RIGHT:
                player.changespeed(-2,0)
                creep.changespeed(-2,0)
            if event.key == pygame.K_UP:
                player.changespeed(0,2)
                creep.changespeed(0,2)
            if event.key == pygame.K_DOWN:
                player.changespeed(0,-2)
                creep.changespeed(0,-2)

        if event.type == pygame.MOUSEBUTTONDOWN and pygame.mouse.get_pressed()[0]:
                for creep in creeps:
                        creep.mouse_click_event(pygame.mouse.get_pos())

                if editMap == True:
                    x,y = pygame.mouse.get_pos()
                    if currentEditTool == "Tree":

                        name = insertTree(x-10,y-25, 10 , 10, "tree")
                        wall_list.add(name)
                        wall_list.draw(screen)          
                        f = open('MapMaker.txt', "a+")
                        image = pygame.image.load("images/map/tree.png").convert()
                        screen.blit(image, (30,10))
                        pygame.display.flip()
                        f.write(str(x) + "," + str(y) + ",790,10, tree\n")
                        #f.write("wall=insertTree(" + str(x) + "," + str(y) + ",790,10)\nwall_list.add(wall)\n")

                    elif currentEditTool == "Rock":

                        name = insertRock(x-10,y-25, 10 , 10,"rock")
                        wall_list.add(name)
                        wall_list.draw(screen)
                        f = open('MapMaker.txt', "a+")
                        f.write(str(x) + "," + str(y) + ",790,10,rock\n")
                        #f.write("wall=insertRock(" + str(x) + "," + str(y) + ",790,10)\nwall_list.add(wall)\n")


                else:
                    None





    #pygame.display.flip()  
    player.update(wall_list)





    movingsprites.draw(screen)
    wall_list.draw(screen)
    pygame.display.flip()

    clock.tick(60)

pygame.quit()

© Game Development or respective owner

Related posts about python

Related posts about pygame