Как обнаружить столкновение змеи с самим собой в игре со змеями, сделанной в pygame - PullRequest
0 голосов
/ 14 февраля 2019

Я делаю игру на змейке на python с pygame, но у меня возникают проблемы с тем, чтобы программа обнаружила столкновение с самим собой ...

Я попытался настроить его так, чтобы он обнаруживал, если бы Моррисон.head обнаружит Morrison.body, но он выдаст мне ошибку

import pygame
import random
import time
import sys
from collections import deque
# Window size
WINDOW_WIDTH=400
WINDOW_HEIGHT=400

pygame.init()
WINDOW  = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ), 
pygame.HWSURFACE|pygame.DOUBLEBUF|pygame.RESIZABLE )
SPRITES = pygame.sprite.Group()

pygame.display.set_caption("Picnic!")
background = pygame.image.load("picnic.png")
background_rect = background.get_rect()
HEAD_IMAGE =pygame.image.load('morrison.png').convert_alpha()
#HEAD_IMAGE.fill(pygame.Color('yellow'))
BODY_IMAGE = pygame.image.load('morrison.png').convert_alpha()
#BODY_IMAGE.fill(pygame.Color('orange'))
FOOD1_IMAGE= pygame.image.load("thinMint.png").convert_alpha()
#FOOD1_IMAGE.fill(pygame.Color('green'))
FOOD2_IMAGE =pygame.image.load("cookie.png").convert_alpha()
#FOOD2_IMAGE.fill(pygame.Color('red'))
FOOD3_IMAGE =pygame.image.load("triscuit.png").convert_alpha()
#FOOD3_IMAGE.fill(pygame.Color('blue'))

clock = pygame.time.Clock()

BLACK = (0,0,0)
score = 0

last_positions = deque(maxlen=10)
def generateFoodPosition():
    pos = random.randrange(1, 40, 1) * 10, random.randrange(1, 40, 
1) * 10
    if pos in last_positions:
        return generateFoodPosition()
    last_positions.append(pos)
    return pos

def draw_text(surf, text, size, x, y):
    font = pygame.font.SysFont("SquidgySweets.otf", 72)
    text_surface = font.render(text, True, BLACK)
    text_rect = text_surface.get_rect()
    text_rect.midtop = (x, y)
    surf.blit(text_surface, text_rect)

class Food(pygame.sprite.Sprite):
    def __init__(self, image, *grps):
        pygame.sprite.Sprite.__init__(self, *grps)
        self.image = image
        self.rect = self.image.get_rect()
        self.rect.center = generateFoodPosition()

    def update(self, dt, snakehead, events):
        global score
        m=1
        if self.rect.colliderect(snakehead):
            print("yeet yah")
            score += 1
            self.rect.center = generateFoodPosition()
            if Morrison.head:
                Morrison.grow(m)
                Morrison.last_grow=Morrison.t

class MorrisonSprite(pygame.sprite.Sprite):
    def __init__( self, part_image, position, head, *grps):
        pygame.sprite.Sprite.__init__(self, *grps)
        self.image = part_image
        self.rect = self.image.get_rect()
        self.rect.center = position
        self.move_step = self.image.get_rect().width # this is how 
we know how many pixels per move step
        self.t = 0
        self.last_move = 0
        self.last_grow = 0
        self.head = head
        self.direction = 'left';
        self.body = []
        if self.head:
            self.body.append(self)
            #self.grow(m)

    def wrapAroundScreen(self):
        # Stay on the screen, and wrap around
        if (self.rect.left >= WINDOW_WIDTH ):
            self.rect.right = 0
        elif (self.rect.right <= 0 ):
            self.rect.left = WINDOW_WIDTH
        if (self.rect.top >= WINDOW_HEIGHT ):
            self.rect.bottom = 0
        elif (self.rect.bottom <= 0):
            self.rect.top = WINDOW_HEIGHT

    def move( self ):
        if ( self.direction == 'up' ):
            self.rect.y -= self.move_step
        elif ( self.direction == 'down' ):
            self.rect.y += self.move_step
        elif ( self.direction == 'left' ):
            self.rect.x -= self.move_step
        elif ( self.direction == 'right' ):
            self.rect.x += self.move_step
        else:
            print(" MOVE ERROR - "+direction)
        self.wrapAroundScreen()

    def update(self, dt, snakehead, events):
        if not self.head:
            return

        keys = pygame.key.get_pressed()
        if ( keys[pygame.K_UP] ):
            self.direction = "up"
        elif ( keys[pygame.K_DOWN] ):
            self.direction =  "down"
        elif ( keys[pygame.K_LEFT] ):
            self.direction = "left"
        elif ( keys[pygame.K_RIGHT] ):
            self.direction = "right"

        self.t += dt
        if any(e for e in events if e.type == pygame.KEYDOWN) or ( 
self.t > 3000 and self.t - self.last_move >= 100 ):
            self.slither()
            self.last_move = self.t

        # Grow every 2 seonds
        #This is a past test function that is no longer used:
        #if (self.t  > 3000 and self.t - self.last_grow >= 10000):
            #print("Growing...")
            #self.grow( 1 )
            #self.last_grow = self.t

    def slither( self ):
        # Move each body part to the location of the previous part
        # So we iterate over the tail-parts in reverse
        for i in range( len( self.body )-1, 0, -1 ):
            self.body[i].rect.center = self.body[i-1].rect.center
        # Move the head
        self.move()

    def getGrowPosition( self ):
        # we grow against self.direction
        # so if we're moving up, the tail grows down
        x,y = self.body[ -1 ].rect.center
        if ( self.direction == 'up' ):
            y += self.move_step
        elif ( self.direction == 'down' ):
            y -= self.move_step
        elif ( self.direction == 'left' ):
            x += self.move_step
        elif ( self.direction == 'right' ):
            x -= self.move_step
        return (x,y)

    def grow( self, by_size=1 ):
        for i in range( by_size ):
            # new body part needs to be added at the tail-position
            new_body_part = MorrisonSprite( BODY_IMAGE, 
self.getGrowPosition(), False, *self.groups())
            self.body.append( new_body_part )

### MAIN
Morrison = MorrisonSprite(HEAD_IMAGE, ((WINDOW_WIDTH//2)-64, 
WINDOW_HEIGHT//2 ), True, SPRITES)
clock = pygame.time.Clock()
done = False
Food(FOOD1_IMAGE, SPRITES)
Food(FOOD2_IMAGE, SPRITES)
Food(FOOD3_IMAGE, SPRITES)
dt = 0
while not done:
    #this allows you to close the window
    events = pygame.event.get()
    for event in events:
        if ( event.type == pygame.QUIT ):
            done = True
        elif ( event.type == pygame.VIDEORESIZE ):
            # this allows you to resize-window:
            WINDOW_WIDTH  = event.w
            WINDOW_HEIGHT = event.h
            WINDOW  = pygame.display.set_mode(( WINDOW_WIDTH, 
WINDOW_HEIGHT ), pygame.HWSURFACE|pygame.DOUBLEBUF|pygame.RESIZABLE)
    #Morrison.head = head
    #Morrison.rect = Morrison.head.get_rect()
    if Morrison.rect.head.colliderect(Morrison.rect.body):
        pygame.quit()

#this basically displays everything on the screen (background, 
sprites)...

    WINDOW.fill(BLACK)
    WINDOW.blit(background, background_rect)
    draw_text(WINDOW, str(score), 18, WINDOW_WIDTH / 2, 10)
    SPRITES.update(dt, Morrison.rect, events)
    SPRITES.draw(WINDOW)
    pygame.display.flip()
    dt = clock.tick_busy_loop(60)

pygame.quit()

Я ожидал, что программа обнаружит столкновение, если столкнется со своим собственным телом, но вместо этого он просто выдаст ошибку

1 Ответ

0 голосов
/ 14 февраля 2019

Как насчет использования функции pygame spritecollide?

# In MorrisonSprite class

def hitMyself( self ):
    hit_by = pygame.sprite.spritecollide( self, SPRITES, False )
    # hit_by includes the head too (always), so just check the count
    if ( len( hit_by ) > 1 ):
        print("HIT")  # debug feedback
        return True
    else:
        return False

РЕДАКТИРОВАТЬ: включение этой функции в основной цикл, кажется, отслеживает попадания OK.

# Main loop
while not done:
    ...
    # Did the snake hit it's tail
    if ( Morrison.hitMyself() == True ):
        done = True
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...