为敌人精灵添加碰撞检测?

时间:2012-11-30 14:10:10

标签: python pygame

我想将玩家精灵使用的相同碰撞检测添加到敌人的精灵或者'creeps'我添加了所有相关的代码我还能看到但仍然没有检测到并处理了碰撞,请在下面的课程中找到,我不知道目前出了什么问题,要碰撞的墙壁列表是'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()

1 个答案:

答案 0 :(得分:1)

Sprite collide是正确的方法,你只是错误地处理返回数据。基本上,如果你是否与组成员发生碰撞,sprite collide将不会返回布尔值。它返回一个精灵列表。基本上,它会给你一个与你在该组中相撞的精灵列表。需要注意的另一件事是列表也总是包含精灵本身。毕竟,它正在与自身发生碰撞。这是一种测试你是否与墙碰撞的有效方法。

def is_colliding_with_wall():                                    #this is a function that will determine if you are touching a wall. You have repeated code to test collisions with walls multiple times, so it is best just to have a function
    collide = pygame.sprite.spritecollide(self, walls, False)    #this gets the list, it is the exact same code as in yours
    for collision in collide:                                    #goes through the list, checking each collision
        if collision != self:                                    #filters out self collision
            return True                                          #if there is a collision that is not self, returns True, that there is a collision with a wall
    return False                                                 #if it has checked all the collisions and there is only a self collision, then it is not colliding with a wall, so it returns False