Как заставить спрайт переместиться в другое место после столкновения в игре со змеями - PullRequest
0 голосов
/ 13 февраля 2019

Я в настоящее время, все еще, работаю над финальным проектом для моего класса Python, и я хочу сделать так, чтобы всякий раз, когда змея пробегала над «тонким монетным двором», программа выводила «yeet yah», а затем тонкий монетный дворпереместится в другое место.

У меня есть функция, которая генерирует позиции продуктов и выводит список, в который я индексирую, чтобы получить координаты x и y этого конкретного элемента питания

import pygame
import random
import time
import sys

# 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!")
HEAD_IMAGE = pygame.image.load('morrison.png').convert_alpha()
BODY_IMAGE = pygame.image.load('morrison.png').convert_alpha()
FOOD1_IMAGE= pygame.image.load("thinMint.png").convert_alpha()
FOOD2_IMAGE = pygame.image.load("cookie.png").convert_alpha()
FOOD3_IMAGE = pygame.image.load("triscuit.png").convert_alpha()
clock = pygame.time.Clock()

BLACK = (0,0,0)

STARTUP_MS = int(time.time() * 1000.0)  # Epoch time programme 
started
NOW_MS= 0  # miliseconds since we started


def generateFoodPosition():
    randFoodX1 = random.randrange(1, 40, 1) * 10
    randFoodY1 = random.randrange(1, 40, 1) * 10
    randFoodX2 = random.randrange(1, 40, 1) * 10
    randFoodY2 = random.randrange(1, 40, 1) * 10
    randFoodX3 = random.randrange(1, 40, 1) * 10
    randFoodY3 = random.randrange(1, 40, 1) * 10
    if randFoodX1 == randFoodX2 or randFoodY1 == randFoodY2 or 
randFoodY2==randFoodY3 or randFoodY1== randFoodY3 or randFoodX2 == 
randFoodX3 or randFoodX3 == randFoodX1:
        generateFoodPosition()
    else:
        return [randFoodX1, randFoodY1, randFoodX2, randFoodY2, 
randFoodX3, randFoodY3]

class ThinMintSprite(pygame.sprite.Sprite):
    def __init__(self, food1_image, position1):
        pygame.sprite.Sprite.__init__(self)
        self.image = food1_image
        self.rect = self.image.get_rect()
        self.rect.center = position1
    def getRect(self):
        return self.rect
    def checkForConsumption(self, snake):
        if self.rect.colliderect(snake):
            print("yeet yah")
            foodPosition[0] = random.randrange(1, 40, 1) * 10
            foodPosition[1] = random.randrange(1, 40, 1) * 10


class ThinMint():
    global SPRITES
    def __init__(self):
        self.food = ThinMintSprite(FOOD1_IMAGE, (foodPosition[0], 
foodPosition[1]))
    self.foodWidth = self.food.image.get_rect().width
    SPRITES.add(self.food)

class CookieSprite(pygame.sprite.Sprite):
    def __init__(self, food2_image, position):
        pygame.sprite.Sprite.__init__(self)
        self.image = food2_image
        self.rect = self.image.get_rect()
        self.rect.center = position
    def getRect(self):
        return self.rect
class Cookie():
    global SPRITES
    def __init__(self):
        self.food = CookieSprite(FOOD2_IMAGE, (foodPosition[2], 
foodPosition[3]))
        self.foodWidth = self.food.image.get_rect().width
        SPRITES.add( self.food )#also thisss piece of code
class TriscuitSprite(pygame.sprite.Sprite):
    def __init__(self, food3_image, position3):
        pygame.sprite.Sprite.__init__(self)
        self.image = food3_image
        self.rect = self.image.get_rect()
        self.rect.center = (position3)
    def getRect(self):
        return self.rect
class Triscuit():
    global SPRITES
    def __init__(self):
        self.food = TriscuitSprite(FOOD3_IMAGE, (foodPosition[4], 
foodPosition[5]))
        self.foodWidth = self.food.image.get_rect().width
        SPRITES.add( self.food )#and this piece


class MorrisonSprite(pygame.sprite.Sprite):
    def __init__( self, part_image, position ):
        pygame.sprite.Sprite.__init__(self)
        self.image = part_image
        self.rect = self.image.get_rect()
        self.rect.center = position
        self.move_step = self.image.get_rect().width # pixels per 
move step

    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, direction ):
        if ( direction == 'up' ):
            self.rect.y -= self.move_step
        elif ( direction == 'down' ):
            self.rect.y += self.move_step
        elif ( direction == 'left' ):
            self.rect.x -= self.move_step
        elif ( direction == 'right' ):
            self.rect.x += self.move_step
        else:
            print(" MOVE ERROR - "+direction)
        self.wrapAroundScreen()


    def moveTo( self, body_part ):
        self.rect.center = body_part.rect.center

    def getRect( self ):
        return self.rect

    def update(self):
        pass


class Morrison():
    def __init__( self, size=3 ):
        global SPRITES
        self.head = MorrisonSprite( HEAD_IMAGE, ( 
(WINDOW_WIDTH//2)-64, WINDOW_HEIGHT//2 ) )
        self.body_size = self.head.image.get_rect().width # pixels 
per move step
        self.direction = 'left';
        self.body = [ self.head ]
        SPRITES.add( self.head )
        self.grow( size )

    def changeDirection( self, new_direction ):
        self.direction = new_direction
        self.slither()

    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].moveTo( self.body[i-1] )
    # Move the head
        self.head.move( self.direction )

    def getGrowPosition( self ):
    # we grow against self.direction
    # so if we're moving up, the tail grows down
        x,y = self.body[ -1 ].getRect().center
        if ( self.direction == 'up' ):
            y += self.body_size
        elif ( self.direction == 'down' ):
            y -= self.body_size
        elif ( self.direction == 'left' ):
            x += self.body_size
        elif ( self.direction == 'right' ):
            x -= self.body_size
        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() )
            self.body.append( new_body_part )
            SPRITES.add( new_body_part )

foodPosition = generateFoodPosition()

def drawGameWindow(screen, sprites):
    global WINDOW_WIDTH, WINDOW_HEIGHT, SPRITES
    screen.fill(BLACK)
    SPRITES.draw(screen)
    pygame.display.update()
    pygame.display.flip()

### MAIN
Morrison = Morrison()
ThinMint = ThinMint()
Cookie=Cookie()
Triscuit = Triscuit()
#TriscuitSprite = TriscuitSprite()
#MorrisonSprite = MorrisonSprite()
##ThinMintSprite = ThinMintSprite()
#CookieSprite=CookieSprite()

last_move = STARTUP_MS
last_grow = STARTUP_MS

clock = pygame.time.Clock()
done = False
while not done:
    NOW_MS = int(time.time() * 1000.0)

    SPRITES.update()


    ThinMint.food.checkForConsumption(Morrison.head)

        # Move every 500ms
    if ( NOW_MS - STARTUP_MS > 3000 and NOW_MS - last_move >= 100 ):
    #print("Moving...")
        Morrison.slither()
        last_move = NOW_MS




# Grow every 2 seonds
    if ( NOW_MS - STARTUP_MS > 3000 and NOW_MS - last_grow >= 10000
):
        print("Growing...")
        Morrison.grow( 1 )
        last_grow = NOW_MS

    for event in pygame.event.get():
        if ( event.type == pygame.QUIT ):
            done = True
        elif ( event.type == pygame.VIDEORESIZE ):
            # 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 
)
        elif (event.type == pygame.KEYDOWN):
            # Movement keys
            keys = pygame.key.get_pressed()
            if ( keys[pygame.K_UP] ):
                Morrison.changeDirection("up")
            elif ( keys[pygame.K_DOWN] ):
                Morrison.changeDirection("down")
            elif ( keys[pygame.K_LEFT] ):
                Morrison.changeDirection("left")
            elif ( keys[pygame.K_RIGHT] ):
                Morrison.changeDirection("right")

    drawGameWindow(WINDOW, SPRITES)
    clock.tick_busy_loop(60)

pygame.quit()

предполагалось, что он напечатает "да йет", и у него тонкое движение мяты, но он печатает только "да йет"

1 Ответ

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

Когда происходит столкновение, вы просто меняете foodPosition[0] и foodPosition[1].Но изменение элементов в этом списке не меняет атрибут rect экземпляра ThinMintSprite.

В целом, я нахожу ваш код запутанным и ненужным комплексом, поэтому я позволил себе немного упростить его:

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!")
HEAD_IMAGE = pygame.Surface((32, 32)) #pygame.image.load('morrison.png').convert_alpha()
HEAD_IMAGE.fill(pygame.Color('yellow'))
BODY_IMAGE = pygame.Surface((32, 32)) #pygame.image.load('morrison.png').convert_alpha()
BODY_IMAGE.fill(pygame.Color('orange'))
FOOD1_IMAGE= pygame.Surface((10, 10)) #pygame.image.load("thinMint.png").convert_alpha()
FOOD1_IMAGE.fill(pygame.Color('green'))
FOOD2_IMAGE = pygame.Surface((10, 10)) #pygame.image.load("cookie.png").convert_alpha()
FOOD2_IMAGE.fill(pygame.Color('red'))
FOOD3_IMAGE = pygame.Surface((10, 10)) #pygame.image.load("triscuit.png").convert_alpha()
FOOD3_IMAGE.fill(pygame.Color('blue'))

clock = pygame.time.Clock()

BLACK = (0,0,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

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):
        if self.rect.colliderect(snakehead):
            print("yeet yah")
            self.rect.center = generateFoodPosition()

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 # 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(3)

    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
        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:

    events = pygame.event.get()
    for event in events:
        if ( event.type == pygame.QUIT ):
            done = True
        elif ( event.type == pygame.VIDEORESIZE ):
            # 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)

    SPRITES.update(dt, Morrison.rect, events)
    WINDOW.fill(BLACK)
    SPRITES.draw(WINDOW)
    pygame.display.flip()
    dt = clock.tick_busy_loop(60)

pygame.quit()

Некоторые примечания:

  • Я изменил изображения на сплошные цветные поверхности, потому что у меня нет ваших изображений, и я хочу запустить свой код, очевидно: -)
  • Я не знаю, почему у вас так много классов.Как у вас есть класс ThinMintSprite, но затем вы создаете другой класс ThinMint, а затем вы создаете экземпляр ThinMint и перезаписываете класс этим экземпляром.
  • 3 (или 6) класса, которые вы создали для еды, в основном одинаковы.Просто создайте один класс и просто передайте ему другие изображения.
  • Нет необходимости создавать глобальный список позиций для всей еды.Пусть каждый экземпляр класса еды сам создает свою позицию.В моем примере выше, я использую deque (который представляет собой просто список с максимальным количеством элементов), чтобы предотвратить нерест пищи в той же позиции
  • Ваша функция generateFoodPosition в любом случае нарушается, потому что когда if оператор True, он не возвращает значение из рекурсивного вызова
  • Я переместил всю логику в классы спрайтов, где они принадлежат IMHO (не в основном цикле)
  • У вас естьрешить, хотите ли вы использовать события для элементов управления или проверить pygame.key.get_pressed().Вы не должны смешивать их.Вы можете двигаться в первые 3 секунды.Это нарочно?Если нет, просто удалите часть any(...) or.
  • Кроме того, игра-змея обычно основана на сетке, что значительно облегчает проверку столкновений и т. Д.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...