微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Pygame:蛇的身体需要跟随头部

如何解决Pygame:蛇的身体需要跟随头部

我一直在使用PyGame用Python开发蛇类游戏。它是众所周知的认传统蛇游戏... 我正在进入第1期,我找不到一种使蛇的身体跟随头部的工作方法。我尝试了很多事情,总是得到相同的结果。

有人可以帮助我找到使身体跟随头部的方法吗? :)

蛇的每个身体部位都包含一个列表,[xPos,yPos,方向,nextDirection]

我现在正在用这段代码移动主体,但这不能正常工作:

      if i == 0:
        pass
      elif i == 1:
        snake[i][3] = snake[0][2]
      else:
        snake[i][3] = snake[i-1][2]

完整代码

import sys
import random

def drawBackground():
  evenOdd = False
  global screenW,screenH,screen,block
  for y in range(int(screenH/block)):
    for x in range(int(screenW/block)):
      if evenOdd == False:
        color = (170,215,81)
        evenOdd = True
      else:
        color = (162,209,73)
        evenOdd = False
      pygame.draw.rect(screen,color,(x * block,y * block,block,block))

def moveSnake():
  global nextDir,snake
  for i in range(len(snake)):
    if snake[i][3] == "LEFT" and snake[i][1] % block == 0:
      snake[i][2] = "LEFT"
      snake[i][3] = ""
    if snake[i][3] == "RIGHT" and snake[i][1] % block == 0:
      snake[i][2] = "RIGHT"
      snake[i][3] = ""
    if snake[i][3] == "UP" and snake[i][0] % block == 0:
      snake[i][2] = "UP"
      snake[i][3] = ""
    if snake[i][3] == "DOWN" and snake[i][0] % block == 0:
      snake[i][2] = "DOWN"
      snake[i][3] = ""
              
    if snake[i][2] == "LEFT":
      snake[i][0] -= 2
    elif snake[i][2] == "UP":
      snake[i][1] -= 2
    elif snake[i][2] == "RIGHT":
      snake[i][0] += 2
    elif snake[i][2] == "DOWN":
      snake[i][1] += 2

    for i in range(len(snake)):
      if i == 0:
        pass
      elif i == 1:
        snake[i][3] = snake[0][2]
      else:
        snake[i][3] = snake[i-1][2]
  


pygame.init()
screen = pygame.display.set_mode((600,600))
clock = pygame.time.Clock()

screenW,screenH = pygame.display.get_surface().get_size()

block = 40

snake = [[200,160,"DOWN",""],[200,120,80,""]]

while True:
  for event in pygame.event.get():
    if event.type == pygame.QUIT:
      pygame.quit()
      sys.exit()
    if event.type == pygame.KEYDOWN:
      if event.key == pygame.K_LEFT and snake[0][2] != "RIGHT":
        snake[0][3] = "LEFT"
      if event.key == pygame.K_UP and snake[0][2] != "DOWN":
        snake[0][3] = "UP"
      if event.key == pygame.K_RIGHT and snake[0][2] != "LEFT":
        snake[0][3] = "RIGHT"
      if event.key == pygame.K_DOWN and snake[0][2] != "UP":
        snake[0][3] = "DOWN"

  moveSnake()

  drawBackground()
  for i in range(len(snake)):
    if i == 0:
      pygame.draw.rect(screen,(70,115,232),(snake[i][0],snake[i][1],block))
    else:
      pygame.draw.rect(screen,(200,100,block))
  
  pygame.display.update()
  clock.tick(120)
  

解决方法

这是您需要的算法的指针-您在正确的轨道上。

认为蛇的身体是(x,y)坐标的数组,对应于蛇的每个片段。第一项(segment[0])是头。第二项(segment[1])是身体的第一部分,依此类推,直到到达尾部(segment[N])。

当蛇移动一帧时,头部向用户指定的某个方向前进。问题是如何处理其余部分(segment[1] - segment[n])?他们跟随头部,每个片段都跟随其前的片段。

所以,一招之后:

  • 段0(头部)移动到用户方向指定的位置
  • 第1段移动到之前由第0段占据的位置
  • 第2段移动到之前由第1段占据的位置
  • ...等等...
  • 第N段移到第N-1段之前占据的位置。

因此,在伪代码中,这看起来像这样:

on a new frame:
  iterating through the segments,starting with the end:
    update segment[n] to have the coordinates of segment[n-1]
  update segments[0] to the new coordinates specified by DIRECTION

希望可以帮助您了解可行的方法。

,

我已对您的代码进行了一些修改,以使用class Snake而不是原始列表来表示蛇体的当前位置。

代替跟踪所有身体部位的方向和下一方向,只需创建头部的下一个位置并去除身体的尾巴即可绘制,这将是更为简单的算法。为此,我使用了deque容器,用户可以从左右两端追加并弹出。

目前,class snake具有3个变量。
direction:蛇(头)的当前方向
body:使用deque容器表示蛇体的当前位置。 [0]作为蛇的头。
timer:使蛇每1/3秒移动一次(如您所愿)

蛇还具有3个功能changeDirection() / moveSnake() / drawSnake()
changeDirection():它的工作原理与您解析键击相同。 moveSnake():它根据头部的当前位置和方向来计算下一个头部应该在哪里。
之后,您只需要将下一个位置附加到body(双端队列)的左侧,然后弹出body的最后一个元素,该元素应为主体的尾部。这将模仿蛇的运动。
drawSnake():它只是将蛇的身体吸引到屏幕上。

希望您靠近class Snake并找到一些有用的东西。

import sys
import random
import pygame
from collections import deque


class Snake:
    def __init__(self):
        self.direction = "DOWN"
        self.body = deque([[200,160],[200,120],80]])
        self.timer = 0
        self.directionChangable = True

    def changeDirection(self,input):
        if not self.directionChangable:
            return
        if input == "LEFT" and self.direction != "RIGHT":
            self.direction = "LEFT"
        if input == "UP" and self.direction != "DOWN":
            self.direction = "UP"
        if input == "RIGHT" and self.direction != "LEFT":
            self.direction = "RIGHT"
        if input == "DOWN" and self.direction != "UP":
            self.direction = "DOWN"
        self.directionChangable = False

    def moveSnake(self):
        self.timer += 1
        if self.timer % block != 0:
            return
        self.directionChangable = True
        self.timer = 0
        nx,ny = self.body[0]
        if self.direction == "UP":
            ny -= block
            if (ny < 0):
                ny = screenH
        elif self.direction == "DOWN":
            ny += block
            if (ny > screenH):
                ny = 0
        elif self.direction == "LEFT":
            nx -= block
            if (nx < 0):
                nx = screenH
        elif self.direction == "RIGHT":
            nx += block
            if (nx > screenW):
                nx = 0
        self.body.appendleft([nx,ny])
        self.body.pop()

    def drawSnake(self):
        pygame.draw.rect(screen,(70,115,232),(self.body[0][0],self.body[0][1],block,block))
        for pos in self.body:
            pygame.draw.rect(screen,(200,100,(pos[0],pos[1],block))


def drawBackground():
    evenOdd = False
    global screenW,screenH,screen,block
    for y in range(int(screenH/block)):
        for x in range(int(screenW/block)):
            if evenOdd is False:
                color = (170,215,81)
                evenOdd = True
            else:
                color = (162,209,73)
                evenOdd = False
            pygame.draw.rect(screen,color,(x * block,y * block,block))


pygame.init()
screen = pygame.display.set_mode((600,600))
clock = pygame.time.Clock()

screenW,screenH = pygame.display.get_surface().get_size()
block = 40


if __name__ == '__main__':
    snake = Snake()
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    snake.changeDirection("LEFT")
                if event.key == pygame.K_UP:
                    snake.changeDirection("UP")
                if event.key == pygame.K_RIGHT:
                    snake.changeDirection("RIGHT")
                if event.key == pygame.K_DOWN:
                    snake.changeDirection("DOWN")

        snake.moveSnake()
        drawBackground()
        snake.drawSnake()

        pygame.display.update()
        clock.tick(120)
,

问题是,当您检查每个线段是否在拐角处(% block == 0)时,所有线段都通过检查,因此所有线段都改变了方向。

要解决此问题,请只允许一个线段在循环中改变方向,以便其他线段继续越过拐角。

这是更新的代码:

def moveSnake():
  global nextDir,snake
  switch = False  # segment changed direction
  for i in range(len(snake)):
    if not switch:
        if snake[i][3] == "LEFT" and snake[i][1] % block == 0:
          snake[i][2] = "LEFT"
          snake[i][3] = ""
          switch = True
          if i<len(snake)-1: snake[i+1][3] = "LEFT"
        if snake[i][3] == "RIGHT" and snake[i][1] % block == 0:
          snake[i][2] = "RIGHT"
          snake[i][3] = ""
          switch = True
          if i<len(snake)-1: snake[i+1][3] = "RIGHT"
        if snake[i][3] == "UP" and snake[i][0] % block == 0:
          snake[i][2] = "UP"
          snake[i][3] = ""
          switch = True
          if i<len(snake)-1: snake[i+1][3] = "UP"
        if snake[i][3] == "DOWN" and snake[i][0] % block == 0:
          snake[i][2] = "DOWN"
          snake[i][3] = ""
          switch = True
          if i<len(snake)-1: snake[i+1][3] = "DOWN"

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。