我怎样才能让蛇长大并链接蛇身体的运动?

2024-12-09 08:30:00
admin
原创
136
摘要:问题描述:我想实现一个蛇游戏。蛇在操场上蜿蜒前行。每当蛇吃到一些食物时,蛇的长度就会增加一个元素。蛇身体的元素像链条一样跟随它的头部。snake_x, snake_y = WIDTH//2, HEIGHT//2 body = [] move_x, move_y = (1, 0) food_x, food_y ...

问题描述:

我想实现一个蛇游戏。蛇在操场上蜿蜒前行。每当蛇吃到一些食物时,蛇的长度就会增加一个元素。蛇身体的元素像链条一样跟随它的头部。

snake_x, snake_y = WIDTH//2, HEIGHT//2
body = []
move_x, move_y = (1, 0)
food_x, food_y = new_food(body)

run = True
while run:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT: move_x, move_y = (-1, 0)
            elif event.key == pygame.K_RIGHT: move_x, move_y = (1, 0)
            elif event.key == pygame.K_UP: move_x, move_y = (0, -1)
            elif event.key == pygame.K_DOWN: move_x, move_y = (0, 1)

    snake_x = (snake_x + move_x) % WIDTH
    snake_y = (snake_y + move_y) % HEIGHT 
    if snake_x == food_x and snake_y == food_y:
        food_x, food_y = new_food(body)
        body.append((snake_x, snake_x))

    # [...]

当蛇头向前移动时,我怎样才能使身体部位跟随蛇头的路径移动?


解决方案 1:

一般来说,你必须区分两种不同类型的。在第一种情况下,蛇在网格中移动,每次移动时,它都会在网格中向前跨出一个区域。在另一种类型中,蛇的位置不在光栅中,也不在网格区域上,位置是自由的,蛇在区域间平滑滑动。

在前一种情况下,身体的每个元素都与网格区域对齐,就像头部一样。另一种则更复杂,因为身体元素的位置取决于元素的大小和蛇头的动态先前位置。


首先是,它被捕捉到网格中。

蛇的元素可以存储在元组列表中。每个元组包含网格中蛇元素的列和行。列表中项目的更改直接跟随蛇的移动。如果蛇移动,则将新位置添加到列表的头部并删除列表的尾部。

例如,我们有一条具有以下元素的蛇:

body = [(3, 3), (3, 4), (4, 4), (5, 4), (6, 4)]

当蛇头从 移动(3, 3)到 ( 3, 2) 时,新的头部位置被添加到列表的头部(body.insert(0, (3, 2)):

body = [(3, 2), (3, 3), (3, 4), (4, 4), (5, 4), (6, 4)]

最后删除 ist 的尾部( del body[-1]):

body = [(3, 2), (3, 3), (3, 4), (4, 4), (5, 4)]

IT科技

最小示例:![IT科技](https://i.sstatic.net/5jD0C.png) repl.it/@Rabbid76/PyGame-SnakeMoveInGrid

IT科技

import pygame
import random

pygame.init()
COLUMNS, ROWS, SIZE = 10, 10, 20
screen = pygame.display.set_mode((COLUMNS*SIZE, ROWS*SIZE))
clock  = pygame.time.Clock()

background = pygame.Surface((COLUMNS*SIZE, ROWS*SIZE))
background.fill((255, 255, 255))
for i in range(1, COLUMNS):
    pygame.draw.line(background, (128, 128, 128), (i*SIZE-1, 0), (i*SIZE-1, ROWS*SIZE), 2)
for i in range(1, ROWS):
    pygame.draw.line(background, (128, 128, 128), (0, i*SIZE-1), (COLUMNS*SIZE, i*SIZE-1), 2)

def random_pos(body):
    while True:
        pos = random.randrange(COLUMNS), random.randrange(ROWS)
        if pos not in body:
            break     
    return pos

length = 1
body = [(COLUMNS//2, ROWS//2)]
dir = (1, 0)
food = random_pos(body)

run = True
while run:
    clock.tick(5)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT: dir = (-1, 0)
            elif event.key == pygame.K_RIGHT: dir = (1, 0)
            elif event.key == pygame.K_UP: dir = (0, -1)
            elif event.key == pygame.K_DOWN: dir = (0, 1)

    body.insert(0, body[0][:])    
    body[0] = (body[0][0] + dir[0]) % COLUMNS, (body[0][1] + dir[1]) % ROWS
    if body[0] == food:
        food = random_pos(body)
        length += 1
    while len(body) > length:
        del body[-1] 
    
    screen.blit(background, (0, 0))
    pygame.draw.rect(screen, (255, 0, 255), (food[0]*SIZE, food[1]*SIZE, SIZE, SIZE))
    for i, pos in enumerate(body):
        color = (255, 0, 0) if i==0 else (0, 192, 0) if (i%2)==0 else (255, 128, 0)
        pygame.draw.rect(screen, color, (pos[0]*SIZE, pos[1]*SIZE, SIZE, SIZE))
    pygame.display.flip()

现在可以完全自由定位。

我们必须在一个列表中跟踪蛇头访问过的所有位置。我们必须将蛇身的元素放置在列表中的位置上,就像链条上的珍珠一样。

IT科技

关键在于计算链中主体的最后一个元素与轨道上后续位置之间的欧几里德距离。当找到距离足够大的新点时,就会将新的珍珠(元素)添加到链(主体)中。

dx, dy = body[-1][0]-pos[0], body[-1][1]-pos[1]
if math.sqrt(dx*dx + dy*dy) >= distance:
    body.append(pos)

以下函数有 3 个参数。track是蛇头位置的列表。no_pearls是蛇身元素的数量,distance是元素之间的欧几里得距离。该函数创建并返回蛇身位置的列表。

def create_body(track, no_pearls, distance):
    body = [(track[0])]
    track_i = 1
    for i in range(1, no_pearls):
        while track_i < len(track):
            pos = track[track_i]
            track_i += 1
            dx, dy = body[-1][0]-pos[0], body[-1][1]-pos[1]
            if math.sqrt(dx*dx + dy*dy) >= distance:
                body.append(pos)
                break
    while len(body) < no_pearls:
        body.append(track[-1])
    del track[track_i:]
    return body

最小示例:![IT科技](https://i.sstatic.net/5jD0C.png) repl.it/@Rabbid76/PyGame-SnakeMoveFree

IT科技

import pygame
import random
import math

pygame.init()
COLUMNS, ROWS, SIZE = 10, 10, 20
WIDTH, HEIGHT = COLUMNS*SIZE, ROWS*SIZE
screen = pygame.display.set_mode((WIDTH, HEIGHT))
clock  = pygame.time.Clock()

background = pygame.Surface((WIDTH, HEIGHT))
background.fill((255, 255, 255))
for i in range(1, COLUMNS):
    pygame.draw.line(background, (128, 128, 128), (i*SIZE-1, 0), (i*SIZE-1, ROWS*SIZE), 2)
for i in range(1, ROWS):
    pygame.draw.line(background, (128, 128, 128), (0, i*SIZE-1), (COLUMNS*SIZE, i*SIZE-1), 2)

def hit(pos_a, pos_b, distance):
    dx, dy = pos_a[0]-pos_b[0], pos_a[1]-pos_b[1]
    return math.sqrt(dx*dx + dy*dy) < distance

def random_pos(body):
    pos = None
    while True:
        pos = random.randint(SIZE//2, WIDTH-SIZE//2), random.randint(SIZE//2, HEIGHT-SIZE//2)
        if not any([hit(pos, bpos, 20) for bpos in body]):
            break    
    return pos

def create_body(track, no_pearls, distance):
    body = [(track[0])]
    track_i = 1
    for i in range(1, no_pearls):
        while track_i < len(track):
            pos = track[track_i]
            track_i += 1
            dx, dy = body[-1][0]-pos[0], body[-1][1]-pos[1]
            if math.sqrt(dx*dx + dy*dy) >= distance:
                body.append(pos)
                break
    while len(body) < no_pearls:
        body.append(track[-1])
    del track[track_i:]
    return body

length = 1
track = [(WIDTH//2, HEIGHT//2)]
dir = (1, 0)
food = random_pos(track)

run = True
while run:
    clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT: dir = (-1, 0)
            elif event.key == pygame.K_RIGHT: dir = (1, 0)
            elif event.key == pygame.K_UP: dir = (0, -1)
            elif event.key == pygame.K_DOWN: dir = (0, 1)

    track.insert(0, track[0][:])    
    track[0] = (track[0][0] + dir[0]) % WIDTH, (track[0][1] + dir[1]) % HEIGHT

    body = create_body(track, length, 20)

    if hit(body[0], food, 20):
        food = random_pos(body)
        length += 1 
        
    screen.blit(background, (0, 0))
    pygame.draw.circle(screen, (255, 0, 255), food, SIZE//2)
    for i, pos in enumerate(body):
        color = (255, 0, 0) if i==0 else (0, 192, 0) if (i%2)==0 else (255, 128, 0)
        pygame.draw.circle(screen, color, pos, SIZE//2)
    pygame.display.flip()
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用