简体   繁体   中英

Pygame Snake Game, getting class to draw on screen

The following code works to a certain extent. You can move the snake body around in any direction but the pellet or apple that it is supposed to eat won't draw on the screen. I would love any advice on how to fix this problem, or how to improve the game.

import sys, pygame, random, itertools, time


blu = (37,102,151)
red = (175,31,36)
bla = (0,0,0)
whi = (255, 255, 255)


pygame.mixer.init()
pygame.mixer.music.load('opening.wav')
pygame.mixer.music.play(-1)


class Board(object):

    def __init__(self, screen):
        self.screen = screen
        self.size = screen.get_size()
        self.bit = 32
        self.keys= []
        self.setStart()


    #sets snake in initial position and put pellet in random position
    def setStart(self):
        width = self.size
        height = self.size
        self.sStart = [20, 20]
        self.snake = Snake(self.sStart)
        self.pellet = Pellet(self.newPelletPosition())

    #runs game and sets snake speed
    def run(self):
        running = time.time()
        pygame.mixer.init()
        pygame.mixer.music.load('FU2.wav')
        pygame.mixer.music.play(-1)
        while True:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    sys.exit()
            self.move()
            now = time.time()
            if now >= running + .20:
                running = now
                self.update()
                if self.boardBoundary() or self.snake.collision():
                    pygame.mixer.music.load('crash.wav')
                    pygame.mixer.music.play()
                    break
                self.draw()

    #allows us to use arrows for playing 
    def move(self):
        keys = pygame.key.get_pressed()
        if sum(keys) != 0:
            self.keys = keys

    #redraws pellet if appears where snake currently is      
    def update(self):
        pelletCollision = self.pellet.position == self.snake.positions[0]
        if pelletCollision:
            self.pellet.position = self.newPelletPosition()
        self.snake.update(self.directionKeys(), pelletCollision)

    #allows us to use arrows while playing
    def directionKeys(self):
        if self.keys[pygame.K_LEFT]:
            return [-self.bit, 0]
        elif self.keys[pygame.K_RIGHT]:
            return [self.bit, 0]
        elif self.keys[pygame.K_UP]:
            return [0, -self.bit]
        elif self.keys[pygame.K_DOWN]:
            return [0, self.bit]
        else:
            return [0, 0]

    #gives pellet random position and avoids overlap with snake 
    def newPelletPosition(self):
        x = self.randomPosition(0)
        y = self.randomPosition(1)
        for pos in self.snake.positions:
            if [x, y] == pos:
                return self.newPelletPosition()
        return [x, y]

This following 3 lines of code doesn't work and I want it to. I rewrote it and somehow managed to get that one to not mess up the game display. Neither def randomPosition 's will draw a pellet on the game screen though.

    #def randomPosition(self, coordinate): 
        #amount_bits = (self.size[coordinate] / self.bit - 1) /
        #return random.randint(bit, max_size / bit) * self.bit

    #!!!random position(this doesn't work)
    def randomPosition(self, coordinate):
        amount_bits = (self.size[coordinate] / self.bit - 1)
        return random.randint(-500, 500) * self.bit

    #see if snakehead hits edge of screen !!
    def boardBoundary(self):
        head_pos_x, head_pos_y = self.snake.positions[0]
        return head_pos_x < 0 or head_pos_x > self.size[0] - self.bit or head_pos_y < 0 or head_pos_y > self.size[1] - self.bit

    #draws screen, pellet, snake
    def draw(self):
        self.screen.fill((bla))
        self.pellet.draw(self.screen)
        self.snake.draw(self.screen)
        pygame.display.flip()

class Snake(object):

    def __init__(self, position, speed = [0,0]):
        self.positions = [position]
        self.speed = speed

    #sets the position as long as the snake hasn't collided (.pop() removes and then returns) 
    def update(self, speed, pelletCollision = False):
        self.set_speed(speed)
        head_pos = self.newHeadPosition()
        self.positions.insert(0, head_pos)
        if not pelletCollision:
            self.positions.pop()

    #updates snake head position 
    def newHeadPosition(self):
        current = self.positions[0]
        return [current[0] + self.speed[0], current[1] + self.speed[1]]

    #sets speed 
    def set_speed(self, speed):
        if speed == [0, 0]:
            pass
        elif self.speed == [0, 0]:
            self.speed = speed
        elif abs(self.speed[0]) != abs(speed[0]):
            self.speed = speed

    #determines if snake collides with itself 
    def collision(self):
        head_pos = self.positions[0]
        for position in self.positions[1:]:
            if position == head_pos:
                return True
        return False

    #draws snake 
    def draw(self, screen):
        bit = pygame.Surface((32, 32))
        bit.fill((whi))
        for position in self.positions:
            screen.blit(bit, position)

class Pellet(object):
    def __init__(self, position):
        self.bit = pygame.Surface((32, 32))
        self.position = position

    def draw(self,screen):
        self.bit.fill((blu))
        screen.blit(self.bit, self.position)

class Menu(object):

    def __init__(self, screen, items, background_color = (bla), font_size = 32, font_color = (whi)):
        self.screen = screen
        self.screen_width = screen.get_rect().width
        self.screen_height = screen.get_rect().height
        self.background_color = background_color
        self.font = pygame.font.SysFont("comicsanms", 32)
        self.font_color = font_color
        self.items = []

        #enumerate makes loop clearer, returns an iterator 
        #for i in range(len(items)):
        #for index, item in enumerate(items):
        for index, item in enumerate(items):
            words = self.font.render(item, 1, font_color)
            width = words.get_rect().width
            height = words.get_rect().height
            pos_x = (self.screen_width / 2) - (width / 2)
            lol = len(items) * height
            pos_y = (self.screen_height / 2) - (lol / 2) + (index * height)
            self.items.append([item, words, (width, height), (pos_x, pos_y)])

    #runs options at the start and end of game 
    def run(self):
        loop = True
        while loop:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    loop = False
                    sys.exit()
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_RETURN:
                        loop = False
                    elif event.key == pygame.K_q:
                        loop = False
                        sys.exit()
            self.screen.fill(self.background_color)
            for name, label, (width, height), (pos_x, pos_y) in self.items:
                self.screen.blit(label, (pos_x, pos_y))
            pygame.display.flip()

#shows us stuff to do on game menu 
def whilerun():
    screen = pygame.display.set_mode((500, 500))

    start_menu_stuff = ['ENTER to play', 'Q to quit']
    end_menu_stuff = ['You Dead, Bro!','ENTER to play again','Q to quit'];     
    start_menu = Menu(screen, start_menu_stuff)
    end_menu = Menu(screen, end_menu_stuff)
    game = Board(screen)

    while True:
        start_menu.run()
        game.run()
        game.setStart()
        end_menu.run()


if __name__ == "__main__":

    pygame.init()
    whilerun()

Any help or direction would be greatly appreciated, this is my first CS class so the code is very, very basic. I just don't know how to get the pellet to actually appear on the screen.

Your def newPelletPosition was always returning [x,y] and also randomPosition returned indexes out of your game world range. You can change the upper limits of the randint function to be more general to accommodate different world sizes.

Changed:

def newPelletPosition(self):
    x = self.randomPosition(0)
    y = self.randomPosition(1)
    for pos in self.snake.positions:
        if [x, y] == pos:
            return self.newPelletPosition()
        else:
            return [x,y]
#!!!random position(this doesn't work)
def randomPosition(self, coordinate):
    amount_bits = (self.size[coordinate] / self.bit - 1)
    return random.randint(0, 500 -32)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM