首页 > 解决方案 > 我试图让我的蛇在不使用 wasd 或箭头键的情况下自动移动

问题描述

我为蛇游戏编写了代码,但现在,我正在尝试编辑该代码以使蛇移动而无需使用按键。我已经尝试编辑我的移动功能并更改 event.type 和 pygame.keydown,但是没有键蛇就不会移动。当我尝试更改代码以使蛇在网格上的某个点自动移动时,蛇在到达坐标后立即自动死亡。

import random
import pygame
import tkinter as tk
from tkinter import messagebox
import sys
import time

pygame.display.set_caption('SNAKE GAME BOT!')

class cube(object):
    rows = 20
    w = 800

    def __init__(self, start, dirnx=1, dirny=0, color=(30,144,255)):
        self.pos = start
        self.dirnx = 1
        self.dirny = 0
        self.color = color

    def move(self, dirnx, dirny):
        self.dirnx = dirnx
        self.dirny = dirny
        self.pos = (self.pos[0] + self.dirnx, self.pos[1] + self.dirny)

    def draw(self, surface, eyes=False):
        dis = self.w // self.rows
        i = self.pos[0]
        j = self.pos[1]

        pygame.draw.rect(surface, self.color, (i * dis + 1, j * dis + 1, dis - 2, dis - 2))
        if eyes:
            centre = dis // 2
            radius = 3
            circleMiddle = (i * dis + centre - radius, j * dis + 8)
            circleMiddle2 = (i * dis + dis - radius * 2, j * dis + 8)
            pygame.draw.circle(surface, (0,128,0), circleMiddle, radius)
            pygame.draw.circle(surface, (0,128,0), circleMiddle2, radius)


class snake(object):
    body = []
    turns = {}

    def __init__(self, color, pos):
        self.color = color
        self.head = cube(pos)
        self.body.append(self.head)
        self.dirnx = 0
        self.dirny = 1
        self.direction = direction

    def move(self):

        for i, c in enumerate(self.body):
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                if event.type == pygame.KEYDOWN:

                    if (event.key == pygame.K_LEFT or event.key == pygame.K_a) and self.direction != "right":
                        self.direction = 'left'
                        self.dirnx = -1
                        self.dirny = 0
                        self.turns[self.head.pos[:]] = [self.dirnx, self.dirny]
                    elif (event.key == pygame.K_RIGHT or event.key == pygame.K_d) and self.direction != "left":
                        self.direction = 'right'
                        self.dirnx = 1
                        self.dirny = 0
                        self.turns[self.head.pos[:]] = [self.dirnx, self.dirny]
                    elif (event.key == pygame.K_UP or event.key == pygame.K_w) and self.direction != "down":
                        self.direction = 'up'
                        self.dirnx = 0
                        self.dirny = -1
                        self.turns[self.head.pos[:]] = [self.dirnx, self.dirny]
                    elif (event.key == pygame.K_DOWN or event.key == pygame.K_s) and self.direction != "up":
                        self.direction = 'down'
                        self.dirnx = 0
                        self.dirny = 1
                        self.turns[self.head.pos[:]] = [self.dirnx, self.dirny]

            p = c.pos[:]
            if p in self.turns:
                turn = self.turns[p]
                c.move(turn[0], turn[1])
                if i == len(self.body) - 1:
                    self.turns.pop(p)

            else:
                reset = (0, 10)
                if c.dirnx == -1 and c.pos[0] <= 0:
                    show_score(0, red, 'times', 75, len(s.body))
                    time.sleep(1)
                    s.reset(reset)
                elif c.dirnx == 1 and c.pos[0] >= c.rows - 1:
                    show_score(0, red, 'times', 75, len(s.body))
                    time.sleep(1)
                    s.reset(reset)
                elif c.dirny == 1 and c.pos[1] >= c.rows - 1:
                    show_score(0, red, 'times', 75, len(s.body))
                    time.sleep(1)
                    s.reset(reset)
                elif c.dirny == -1 and c.pos[1] <= 0:
                    show_score(0, red, 'times', 75, len(s.body))
                    time.sleep(1)
                    s.reset(reset)
                else:
                    c.move(c.dirnx, c.dirny)

    def reset(self, pos):
        self.head = cube(pos)
        self.body = []
        self.body.append(self.head)
        self.turns = {}
        self.dirnx = 0
        self.dirny = 1

    def addCube(self):
        tail = self.body[-1]
        dx, dy = tail.dirnx, tail.dirny

        if dx == 1 and dy == 0:
            self.body.append(cube((tail.pos[0] - 1, tail.pos[1])))
        elif dx == -1 and dy == 0:
            self.body.append(cube((tail.pos[0] + 1, tail.pos[1])))
        elif dx == 0 and dy == 1:
            self.body.append(cube((tail.pos[0], tail.pos[1] - 1)))
        elif dx == 0 and dy == -1:
            self.body.append(cube((tail.pos[0], tail.pos[1] + 1)))

        self.body[-1].dirnx = dx
        self.body[-1].dirny = dy

    def draw(self, surface):
        for i, c in enumerate(self.body):
            if i == 0:
                c.draw(surface, True)
            else:
                c.draw(surface)


def drawGrid(w, rows, surface):
    sizeBtwn = w // rows

    x = 0
    y = 0
    for l in range(rows):
        x = x + sizeBtwn
        y = y + sizeBtwn

        pygame.draw.line(surface, (255, 255, 255), (x, 0), (x, w))
        pygame.draw.line(surface, (255, 255, 255), (0, y), (w, y))


def redrawWindow(surface):
    global rows, width, s, snack
    surface.fill((154,205,50))
    s.draw(surface)
    snack.draw(surface)
    drawGrid(width, rows, surface)
    pygame.display.update()


def randomSnack(rows, item):
    positions = item.body

    while True:
        x = random.randrange(rows)
        y = random.randrange(rows)
        if len(list(filter(lambda z: z.pos == (x, y), positions))) > 0:
            continue
        else:
            break

    return (x, y)


def message_box(subject, content):
    root = tk.Tk()
    root.attributes("-topmost", True)
    root.withdraw()
    messagebox.showinfo(subject, content)
    try:
        root.destroy()
    except:
        pass


def show_score(choice, color, font, size, score):
    score_font = pygame.font.SysFont(font, size)
    score_surface = score_font.render('BOTS SCORE : ' + str(score), True, color)
    score_rect = score_surface.get_rect()
    if choice == 1:
        score_rect.midtop = (60, 60)
    else:
        score_rect.midtop = (400, 400)
    win.blit(score_surface, score_rect)
    pygame.display.flip()

def main():
    global width, rows, s, snack, win, direction, red
    direction = 'right'
    width = 800
    rows = 20
    red = pygame.Color(255, 0, 0)
    check_errors = pygame.init()
    if check_errors[1] > 0:
        print(f'[!] Had {check_errors[1]} errors when initializing game, exiting...')
        sys.exit(-1)
    else:
        print('[+] Game successfully initialized')

    win = pygame.display.set_mode((width, width))
    s = snake((30,144,255), (0, 10))
    snack = cube(randomSnack(rows, s), color=(255, 0, 0))
    flag = True

    clock = pygame.time.Clock()

    while flag:
        pygame.time.delay(1)
        clock.tick(10)

        s.move()
        if s.body[0].pos == snack.pos:
            s.addCube()
            snack = cube(randomSnack(rows, s), color=(255, 0, 0))

        for x in range(len(s.body)):
            if s.body[x].pos in list(map(lambda z: z.pos, s.body[x + 1:])):
                show_score(0, red, 'times', 80, len(s.body))
                print('BOTS SCORE: ', len(s.body))
                time.sleep(1)
                s.reset((0, 10))
                break

        redrawWindow(win)


main()

请帮忙!

标签: pythonpygame

解决方案


import pygame
import random
import os
from Snake import Snake
from Food import Food
from Block import Block
from World import worlds

from tkinter import *
import tkinter.simpledialog

head_path = os.path.join('Assets','Images','head.png')
index3_path = os.path.join('Assets','Images','index3.jpg')
python_path = os.path.join( 'Assets','Images','python.jpg')
point_path = os.path.join('Assets','Sounds','Point.wav')
pygame.mixer.pre_init(44100, -16, 2, 2048)
pygame.mixer.init()
pygame.init()
#intiating sounds
intro_sound = pygame.mixer.Sound(os.path.join('Assets','Sounds','intro.wav'))
game_sound = pygame.mixer.Sound(os.path.join('Assets','Sounds','gamesound.wav'))
pause_sound = pygame.mixer.Sound(os.path.join('Assets','Sounds','pausesound.wav'))
endgame_sound = pygame.mixer.Sound(os.path.join('Assets','Sounds','endsound.wav'))
#the volume are set such that sounds are pleasant
intro_sound.set_volume(0.1)
game_sound.set_volume(0.6)
pause_sound.set_volume(0.1)
endgame_sound.set_volume(0.12)

width, height = 1000, 600
game_display = pygame.display.set_mode((width, height))
game_display.fill((170,150,255))
blist=[]

pygame.display.set_caption('SNAKES')
img = pygame.image.load(head_path)
pygame.display.set_icon(img)
dirn = "right"
clock = pygame.time.Clock()
font = pygame.font.SysFont("comicsansms", 35)
FPS = 25


def total(score, i):
    """ function for total score """
    return score + i * 10


# for highscore
highscorefile = open('highscore.txt', 'rt')
highscore = highscorefile.readline()
try:
    highscore = int(highscore)
except ValueError:
    highscore = 0
namehighscore = highscorefile.readline()
highscorefile.close()


def pause(scorestr):
    #stop in game music and play pause music
    game_sound.stop()
    pause_sound.play(-1) 
    paused = True
    while paused:    
        showButton()
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
            keyp = action()
            if event.type == pygame.KEYDOWN or keyp != None:
                try:
                    if keyp == 'c' or event.key == pygame.K_c:
                        paused = False
                except:
                    pass
                try:
                    if keyp == 'q' or event.key == pygame.K_q:
                        print('quit')
                        pygame.quit()
                        quit()
                except:
                    pass
                    
        message("Paused", (0, 0, 0))
        message("C to continue, Q to Quit", (200, 0, 0), 40)
        # display score on pause
        message(scorestr, (255, 0, 0), 80)
        pygame.display.update()
        clock.tick(5)
    #stop pause music and play in game music if game continues
    if paused == False:
        pause_sound.stop()
        game_sound.play(-1)

def button(msg,x,y,w,h):
    mouse = pygame.mouse.get_pos()

    if x+w > mouse[0] > x and y+h > mouse[1] > y:
        pygame.draw.rect(game_display, (0,0,250),(x,y,w,h))
    else:
        pygame.draw.rect(game_display, (0,0,100),(x,y,w,h))
    smallText = pygame.font.Font("freesansbold.ttf",20)
    text= smallText.render(msg, True, (0,200,0))
    t=text.get_rect()
    t.center = ( (x+(w/2)), (y+(h/2)) )
    game_display.blit(text, t)

def intro():
    #play intro music infinite loop
    intro_sound.play(-1)
    i=True
    while i:
        for event in pygame.event.get():
            keyp=action()
            if event.type==pygame.QUIT:
                pygame.quit()
                quit()
            if keyp!=None or event.type==pygame.KEYDOWN :
                try:
                    if keyp=='c' or event.key==pygame.K_c :
                        i=False
                except:
                    continue
        showButton()
        image = pygame.image.load(index3_path)
        game_display.blit(image,(0,0))
        message("   Welcome to Snakes!!",(200,0,0),-59)
        message("Press C to continue",(100,0,100),260)
        pygame.display.update()
        clock.tick(15)

def showButton():
    global blist
    pygame.draw.rect(game_display, (170, 150, 255), (800, 0, 200, 600))
    button("Continue", 800, 200, 130, 30)
    blist.append((800, 200, 130, 30,'c'))
    button("Exit", 935, 200, 65, 30)
    blist.append((935, 200, 65, 30,'q'))
    button("Up", 870, 235, 50, 30)
    blist.append((870, 235, 50, 30,'up'))
    button("Down", 865, 305, 60, 30)
    blist.append((865, 305, 60, 30,'dn'))
    button("Right", 895, 270, 60, 30)
    blist.append((895, 270, 60, 30,'rt'))
    button("Left", 830, 270, 60, 30)
    blist.append((830, 270, 60, 30,'lt'))
    button("Pause",830,340,125,30)
    blist.append((830,340,125,30,'p'))
    button("Shift", 830, 375, 125, 30)
    blist.append((830, 375, 125, 30,'st'))
    pygame.draw.line(game_display,(0,200,100),(800,0),(800,600),5)

def action():
    global blist
    mouse = pygame.mouse.get_pos()
    click = pygame.mouse.get_pressed()
    for tup in blist:
        if tup[0] + tup[2] > mouse[0] > tup[0] and tup[1] + tup[3] > mouse[1] > tup[1]:
            if click[0] == 1:
                return tup[4]
    return None

def message(m, color, dispy=0):
    text = font.render(m, True, color)
    t = text.get_rect()
    t.center = (400), (300) + dispy
    game_display.blit(text, t)


def food_collides_block(food_rect, blocks):
    """ Returns True if any of the blocks collide with the food """

    for block in blocks:
        if food_rect.colliderect(block.get_rect()):
            return True

    return False


def get_blocks(food_rect, n):
    """ Generates `n` blocks at random x, y """

    blocks = list()
    for i in range(n):
        block_x = round(random.randrange(0, (width)) / 10.0) * 10
        block_y = round(random.randrange(0, height) / 10.0) * 10

        block_width, block_height = 10, 10
        block = Block(block_x, block_y, block_width, block_height)

        # if the block collides with food, generate at other x, y.
        if food_rect.colliderect(block.get_rect()):
            i -= 1
            continue

        blocks.append(block)

    return blocks


def gameLoop():
    global dirn, k, highscore, namehighscore
    pyExit = False
    pyOver = False
    #stop intro music and play in game music infinite loop
    intro_sound.stop()
    game_sound.play(-1)
    score = 0
    world_num = 0
    scorestr = "Score:0"
    # Initialize the game
    snake = Snake(200, 200, img)
    food = Food(int(width / 2), int(height / 2))
    blocks = worlds(width - 200, height, world_num)

    # Keeps track of the direction of the snake.
    dx, dy = 0, 0
    lossreason = ''

    while not pyExit:
        if pyOver == True:
            #play end music
            endgame_sound.play(-1)
        while pyOver:
            image = pygame.image.load(python_path)
            game_display.blit(image, (0, 0))

            message("Game Over! Press C to play Again, Q to Quit",
                    (255, 0, 0), -20)
            message(lossreason, (255, 0, 0), 30)
            # display score on game over
            message("Your" + scorestr, (255, 0, 0), 80)
            if totalscore > highscore:
                # message("Highscore!!!",(255,0,0),120)
                # write new highscore
                highscorefile = open('highscore.txt', 'wt')
                highscorefile.write(str(totalscore) + "\n")

                # name window
                def namewrite():
                    highscorefile.write(v.get())
                    scorewindow.destroy()

                scorewindow = Tk()
                scorewindow.geometry('300x100')
                frame = Frame(scorewindow, width=100, height=100)
                frame.pack()
                scorewindow.title("congratulations")

                Label(frame, text='you\'ve made highscore!!!!').pack(side='top')
                v = StringVar()
                v.set("type your name")
                textbox = Entry(frame, textvariable=v)
                textbox.pack(side='top')

                okbutton = Button(frame, text="ok", fg="black",
                                  bg="white", command=namewrite)
                okbutton.pack(side='bottom')

                scorewindow.mainloop()
                highscorefile.close()

                # incase user wants to countinue after creating highscore
                # to read his new score
                highscorefile = open('highscore.txt', 'rt')
                highscore = highscorefile.readline()
                highscore = int(highscore)
                namehighscore = highscorefile.readline()
                highscorefile.close()

            else:
                message("Highscore by " + namehighscore +
                        ":" + str(highscore), (255, 0, 0), 120)
            pygame.display.update()

            for event in pygame.event.get():
                keyp = action()
                if keyp != None or event.type == pygame.KEYDOWN:
                    try:
                        if keyp == 'q' or event.key == pygame.K_q:
                            pyExit = True
                            pyOver = False
                    except:
                        blank = []  # bypass the exception
                    try:
                        if keyp == 'c' or event.key == pygame.K_c:
                            #stop endgame music
                            endgame_sound.stop()
                            gameLoop()
                    except:
                        blank = []  # bypass the exception
                        
        """ Events """
        #the conditions are modified to work with the buttons
        for event in pygame.event.get():
            keyp = action()
            # blank is not used anywhere
            # it is just used to jump the exception
            if event.type == pygame.QUIT:
                pyExit = True
            if event.type == pygame.KEYDOWN or keyp != None:
                try:
                    if keyp == 'lt' or event.key == pygame.K_LEFT and dirn != "right":
                        dirn = "left"
                        dx = -1
                        dy = 0
                except:
                    blank = []
                try:
                    if keyp == 'rt' or event.key == pygame.K_RIGHT and dirn != "left":
                        dirn = "right"
                        dx = 1
                        dy = 0
                except:
                    blank = []
                try:
                    if keyp == 'up' or event.key == pygame.K_UP and dirn != "down":
                        dirn = "up"
                        dy = -1
                        dx = 0
                except:
                    blank = []
                try:
                    if keyp == 'dn' or event.key == pygame.K_DOWN and dirn != "up":
                        dirn = "down"
                        dy = 1
                        dx = 0
                except:
                    blank = []
                try:
                    if keyp == 'p' or event.key == pygame.K_p:
                        pause(scorestr)
                except:
                    blank = []
                try:
                    if keyp == 'q' or event.key == pygame.K_q:
                        pygame.quit()
                        quit(0)
                except:
                    blank = []

        # level changer value
        if score > 10:
            score = 0
            world_num += 1
            blocks = worlds(width - 200, height, world_num)
            food.x, food.y = int(width / 2), int(height / 2)

        # Engage boost of pressing shift
        keyp=action()
        keyPresses = pygame.key.get_pressed()
        boost_speed = keyPresses[pygame.K_LSHIFT] or keyPresses[pygame.K_RSHIFT] or keyp=='st'

        # if boost_speed is true it will move 2 blocks in one gameloop
        # else it will just move one block
        iterations = [1]
        if boost_speed == 1:
            iterations.append(2)

        for i in iterations:
            """ Update snake """
            snake.move(dx, dy, 10)
            snake.check_boundary(width, height)

            snake_rect = snake.get_rect()
            food_rect = food.get_rect()

            """ Snake-Snake collision """
            if snake.ate_itself():
                #stop game sound
                game_sound.stop()
                pyOver = True
                lossreason = 'Oooops You Hit YOURSELF'
                

            """ Snake-Block collision """
            for block in blocks:
                block_rect = block.get_rect()
                if block_rect.colliderect(snake_rect):
                    #stop game sound
                    game_sound.stop()
                    pyOver = True
                    lossreason = 'Ooops You Hit a BLOCKER'
                    
            """ Snake-Food collision """
            # if snake collides with food, increase its length.
            if food_rect.colliderect(snake_rect):
                score += 1
                snake.increment_length()

                sound = pygame.mixer.Sound(point_path)
                sound.set_volume(0.3)
                sound.play()

                # generate food at random x, y.
                food.generate_food(width, height)

                # try generating the food at a position where blocks are not present.
                while food_collides_block(food.get_rect(), blocks):
                    food.generate_food(width - food.size, height - food.size)

            """ Draw """
            game_display.fill((255, 255, 255))
            showButton()

            # draw the food and snake.
            snake.draw(game_display, dirn, (0, 155, 0))
            food.draw(game_display, (0, 255, 0))

        # draw the blocks.
        for block in blocks:
            block.draw(game_display, (255, 0, 0))
        # count and display score on screen
        totalscore = total(score, world_num)
        scorestr = 'Score: ' + str(totalscore)
        font = pygame.font.SysFont(None, 30)
        text = font.render(scorestr, True, (0, 0, 255))
        game_display.blit(text, (0, 0, 20, 20))

        pygame.display.update()
        clock.tick(FPS)

    pygame.quit()
    quit()


intro()
gameLoop()

推荐阅读