@flozer

Как добиться плавности движения змейки?

Создал простую змейку на pygame и хочу чтобы змейка не телепортировалась, а плавно передвигалась. Помогите пожалуйста
import time

import pygame
import random
from os import path

WIDTH = 500
HEIGHT = 500
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
BLACK = (0, 0, 0)
PURPLE = (182, 0, 255)
YELLOW = (255, 255, 0)
ORANGE = (255, 186, 0)
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption('КРЫСКА ГЕРБИЛ')
snake_block = 20
score = 0
score_font = pygame.font.SysFont('comicsansms', 35)


sound1 = pygame.mixer.Sound('music/pacman wakka.wav')
sound1.set_volume(0.9)
pygame.mixer.music.load(path.join('music/musfon.wav'))
pygame.mixer.music.set_volume(0.5)


ycor = round(WIDTH / (2 * snake_block)) * snake_block
xcor = round(HEIGHT / (2 * snake_block)) * snake_block
x = 0
y = 0
snake_speed = 4
snake_body = []
length = 2

foodx = round(random.randrange(0, WIDTH - snake_block) / snake_block) * snake_block
foody = round(random.randrange(0, HEIGHT - snake_block) / snake_block) * snake_block

bg_img = pygame.image.load(path.join('img/бг.png')).convert()
bg = pygame.transform.scale(bg_img, (WIDTH, HEIGHT))
bg_rect = bg.get_rect()


food_img = pygame.image.load(path.join('img/гербил.gif')).convert()
food = pygame.transform.scale(food_img, (snake_block, snake_block))
food.set_colorkey(WHITE)
food_rect = food.get_rect(x=foodx, y=foody)
run = True
clock = pygame.time.Clock()
head_imges = [pygame.image.load(path.join('img/голова вверх.png')).convert(),
              pygame.image.load(path.join('img/голова вниз.png')).convert(),
              pygame.image.load(path.join('img/голова лево.png')).convert(),
              pygame.image.load(path.join('img/голова право.png')).convert()]


tail_imges = [pygame.image.load(path.join('img/хвост вниз.png')).convert(),
              pygame.image.load(path.join('img/хвост вверх.png')).convert(),
              pygame.image.load(path.join('img/хвост право.png')).convert(),
              pygame.image.load(path.join('img/хвост лево.png')).convert()]


flag = 0


def draw_head(i, snake_body):
    snake_head_img = head_imges[i]
    snake_head = pygame.transform.scale(snake_head_img, (snake_block, snake_block))
    snake_head.set_colorkey(BLACK)
    snake_head_rect = snake_head.get_rect(x=snake_body[-1][0], y=snake_body[-1][1])
    screen.blit(snake_head, snake_head_rect)


def draw_tail(i, snake_body):
    snake_tail_img = tail_imges[i]
    snake_tail = pygame.transform.scale(snake_tail_img, (snake_block, snake_block))
    snake_tail.set_colorkey(BLACK)
    snake_tail_rect = snake_tail.get_rect(x=snake_body[0][0], y=snake_body[0][1])
    screen.blit(snake_tail, snake_tail_rect)


def score_1(score):
    global vaule_score
    vaule_score = score_font.render('Счёт: ' + str(score), True, WHITE)
    screen.blit(vaule_score, [0, 0])


pygame.mixer.music.play()
time.sleep(3)
while run:
    try:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    x = -snake_block
                    y = 0
                    flag = 2
                elif event.key == pygame.K_RIGHT:
                    x = snake_block
                    y = 0
                    flag = 3
                elif event.key == pygame.K_UP:
                    x = 0
                    y = -snake_block
                    flag = 0
                elif event.key == pygame.K_DOWN:
                    x = 0
                    y = snake_block
                    flag = 1
                elif event.key == pygame.K_BACKSPACE:
                    run = False
        if xcor >= WIDTH or xcor < 0 or ycor >= HEIGHT or ycor < 0:
            run = False
        xcor += x
        ycor += y

        screen.blit(bg, bg_rect)
        screen.blit(food, food_rect)

        snake_head = [xcor, ycor]
        snake_body.append(snake_head)
        if len(snake_body) > length:
            del snake_body[0]
        for i in snake_body[1:-1]:
            if flag == 2 or flag == 3:
                snake_img = pygame.image.load(path.join('img/тело гориз.png'))
            if flag == 0 or flag == 1:
                snake_img = pygame.image.load(path.join('img/тело верт.png'))
            snake = pygame.transform.scale(snake_img, (snake_block, snake_block))
            snake.set_colorkey(WHITE)
            screen.blit(snake, (i[0], i[1]))
        draw_tail(flag, snake_body)
        draw_head(flag, snake_body)
        score_1(length - 1)
    # pygame.draw.rect(screen, BLUE, (i[0], i[1], snake_block, snake_block))
        if xcor == foodx and ycor == foody:
            foody = round(random.randrange(0, HEIGHT - snake_block) / snake_block) * snake_block
            foodx = round(random.randrange(0, WIDTH - snake_block) / snake_block) * snake_block
            length += 1
            food_img = pygame.image.load(path.join('img/гербил.gif')).convert()
            food = pygame.transform.scale(food_img, (snake_block, snake_block))
            food.set_colorkey(WHITE)
            food_rect = food.get_rect(x=foodx, y=foody)
            score += 1
            sound1.play()
            snake_speed += 2

        for z in snake_body[:-1]:
            if z == snake_head:
                run = False
        pygame.display.update()
        pygame.display.flip()
        screen.fill(PURPLE)
        clock.tick(snake_speed)
    except FileNotFoundError or SyntaxError or IndentationError or\
            InterruptedError or IndexError or ImportError or ValueError or\
            FloatingPointError or KeyError or KeyboardInterrupt or\
            TypeError or TabError or Exception or LookupError:
        screen.blit(bg, bg_rect)
        font_style = pygame.font.SysFont('text', 40)
        mesg = font_style.render('ОШИБКА', True, RED)
        error = font_style.render('Упс...', True, WHITE)
        screen.blit(error, [215, 185])
        screen.blit(mesg, [180, 225])
        time.sleep(2)

    else:
        font_style = pygame.font.SysFont('text', 40)
        screen.blit(bg, bg_rect)
        screen.blit(vaule_score, [190, 170])
        mesg = font_style.render('Змейка сдохла', True, RED)
        screen.blit(mesg, [150, 225])


pygame.display.update()
time.sleep(3)
pygame.quit()
  • Вопрос задан
  • 197 просмотров
Пригласить эксперта
Ответы на вопрос 1
trapwalker
@trapwalker
Программист, энтузиаст
Придётся довольно глубоко менять вашу "Змейку", чтобы она плавно двигалась.
Для этого ваш тик перемещения нужно разбить на число подтиков, соответствующих числу пикселей вашей игровой ячейки. В вашем случае это 20.
То есть ваша змея должна отрисовываться в 20 раз чаще. При этом тело змеи будет по-прежнему дискретным, просто добавится ещё один вложенный счетчик.
Внешний счетчик как и сейчас будет считать шаги змеи, а внутренний будет считать шаги анимации перемещения внутри одного шага змеи. На протяжении анимации перемещения каждый сегмент змеи попиксельно перемещается от своих координат на предыдущем шаге к своим координатам на следующем. Ничего сложного.

Но ваш код уже плохо читается. Такой код называют спагетти-кодом.
Можно вынести структуру данных состояния змеи в отдельный класс и отрисовку реализовать отдельным методом, куда снаружи передавать шаг анимации.
Тогда у вас будет разделено логическое перемещение змеи по сегментом, и чисто декоративное по пикселям.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы