You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Pygame贪吃蛇游戏中实现蛇的穿墙传送功能?

问题

刚接触编程,正在制作一款简易贪吃蛇游戏,参考了Edurika的教程,但教程未涵盖蛇的穿墙传送功能,自己无法实现。这是课程作业,希望有人帮忙解决该问题,也欢迎任何改进建议。以下是我的代码:

import pygame
import time
import random
 
pygame.init()


white = (255, 255, 255)
yellow = (255, 255, 102)
black = (0, 0, 0)
red = (213, 50, 80)
green = (0, 255, 0)
blue = (50, 153, 213)


dis_width = 400
dis_height = 500
 
dis = pygame.display.set_mode((dis_width, dis_height))
pygame.display.set_caption('SNELIAS')
 
clock = pygame.time.Clock()
 
snake_block = 10
snake_speed = 8
 
font_style = pygame.font.SysFont("bahnschrift", 25)
score_font = pygame.font.SysFont("comicsansms", 35)
 
 
def Your_score(score):
    value = score_font.render("Your Score: " + str(score), True, yellow)
    dis.blit(value, [0, 0])
 
 
def our_snake(snake_block, snake_list):
    for x in snake_list:
        pygame.draw.rect(dis, black, [x[0], x[1], snake_block, snake_block])
 
 
def message(msg, color):
    mesg = font_style.render(msg, True, color)
    dis.blit(mesg, [dis_width / 6, dis_height / 3])
 
 
def gameLoop():
    game_over = False
    game_close = False
 
    x1 = dis_width / 2
    y1 = dis_height / 2
 
    x1_change = 0
    y1_change = 0
 
    snake_List = []
    Length_of_snake = 1
 
    foodx = round(random.randrange(0, dis_width - snake_block) / 10.0) * 10.0
    foody = round(random.randrange(0, dis_height - snake_block) / 10.0) * 10.0

    image = pygame.image.load("snakegrnd.jpeg")
    screenUpdate = pygame.transform.scale(image, (dis_width, dis_height))

  
    while not game_over:
        dis.blit(screenUpdate, (0, 0))
      
        while game_close == True:
            message("You Lost! Press C-Play Again or Q-Quit", white)
            Your_score(Length_of_snake - 1)
            pygame.display.update()
 
            for event in pygame.event.get():
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_q:
                        game_over = True
                        game_close = False
                    if event.key == pygame.K_c:
                        gameLoop()
 
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                game_over = True
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    x1_change = -snake_block
                    y1_change = 0
                elif event.key == pygame.K_RIGHT:
                    x1_change = snake_block
                    y1_change = 0
                elif event.key == pygame.K_UP:
                    y1_change = -snake_block
                    x1_change = 0
                elif event.key == pygame.K_DOWN:
                    y1_change = snake_block
                    x1_change = 0
 
        if x1 >= dis_width or x1 < 0 or y1 >= dis_height or y1 < 0:
            game_close = True
        x1 += x1_change
        y1 += y1_change
        pygame.draw.rect(dis, green, [foodx, foody, snake_block, snake_block])
        snake_Head = []
        snake_Head.append(x1)
        snake_Head.append(y1)
        snake_List.append(snake_Head)
        if len(snake_List) > Length_of_snake:
            del snake_List[0]
 
        for x in snake_List[:-1]:
            if x == snake_Head:
                game_close = True
 
        our_snake(snake_block, snake_List)
        Your_score(Length_of_snake - 1)
 
        pygame.display.update()
 
        if x1 == foodx and y1 == foody:
            foodx = round(random.randrange(0, dis_width - snake_block) / 10.0) * 10.0
            foody = round(random.randrange(0, dis_height - snake_block) / 10.0) * 10.0
            Length_of_snake += 1
 
        clock.tick(snake_speed)
 
    pygame.quit()
    quit()
 
 
gameLoop()
解决方案与改进建议

一、实现穿墙传送功能

原代码中碰到边界会直接触发游戏结束,只需替换边界判断逻辑为传送即可:

找到这段代码:

if x1 >= dis_width or x1 < 0 or y1 >= dis_height or y1 < 0:
    game_close = True
x1 += x1_change
y1 += y1_change

修改为:

# 先更新位置
x1 += x1_change
y1 += y1_change

# 穿墙传送逻辑
if x1 >= dis_width:
    x1 = 0
elif x1 < 0:
    x1 = dis_width - snake_block
if y1 >= dis_height:
    y1 = 0
elif y1 < 0:
    y1 = dis_height - snake_block

说明:必须先更新位置再判断边界,这样蛇头完全超出边界后才会触发传送;x方向传送到对面时要减去snake_block,避免蛇头部分露出边界(因为蛇块大小是10,直接设为0或dis_width会导致绘制时出界)。

二、其他改进建议

  • 避免递归重启游戏:原代码中按C重启时调用gameLoop()属于递归,多次重启会导致栈溢出。建议把重启逻辑改成重置变量而非递归,比如:
    # 替换原来的if event.key == pygame.K_c: gameLoop()
    if event.key == pygame.K_c:
        # 重置所有游戏状态变量
        x1 = dis_width / 2
        y1 = dis_height / 2
        x1_change = 0
        y1_change = 0
        snake_List = []
        Length_of_snake = 1
        foodx = round(random.randrange(0, dis_width - snake_block)/10.0)*10.0
        foody = round(random.randrange(0, dis_height - snake_block)/10.0)*10.0
        game_close = False
    
  • 防止食物生成在蛇身上:当前食物随机生成可能直接出现在蛇身,导致无法吃到。可以添加循环判断,直到食物位置不在蛇列表中:
    # 生成食物时替换原代码
    while True:
        foodx = round(random.randrange(0, dis_width - snake_block)/10.0)*10.0
        foody = round(random.randrange(0, dis_height - snake_block)/10.0)*10.0
        # 检查食物是否在蛇身上
        if [foodx, foody] not in snake_List:
            break
    
  • 禁止反向移动:当前可以直接按相反方向键让蛇撞自己,比如向左走时按右键,蛇会立刻掉头撞身体。可以添加判断,禁止直接反向:
    # 按键处理时修改
    if event.key == pygame.K_LEFT:
        if x1_change != snake_block:  # 当前不是向右移动
            x1_change = -snake_block
            y1_change = 0
    elif event.key == pygame.K_RIGHT:
        if x1_change != -snake_block:  # 当前不是向左移动
            x1_change = snake_block
            y1_change = 0
    elif event.key == pygame.K_UP:
        if y1_change != snake_block:  # 当前不是向下移动
            y1_change = -snake_block
            x1_change = 0
    elif event.key == pygame.K_DOWN:
        if y1_change != -snake_block:  # 当前不是向上移动
            y1_change = snake_block
            x1_change = 0
    
  • 优化背景图加载:把背景图加载放到gameLoop()外面,避免每次重启游戏都重新加载图片,提升性能。
  • 添加音效:可以在吃到食物、游戏结束时添加简单音效,增强体验。

内容的提问来源于stack exchange,提问作者E_stkvs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 22:49:59