如何使用PyGame为蛇和梯子创建10x10板?

2024-04-20 11:24:55 发布

您现在位置:Python中文网/ 问答频道 /正文

我以前从未使用过Pygame,但在我的项目中,我决定创建一个游戏“蛇和梯子”,它是一个棋盘游戏,通常有大约100个方格,并为用户提供计数器/棋子。它有一个骰子你可以控制你移动的空间,如果你在梯子上着陆,它会把你带到你之前的某个位置,如果你在蛇上着陆,它会把你带到你现在所在位置的后面。它通常由2-4个玩家玩。你知道吗

我在想,我怎么能用Pygame创建一个10*10的数字网格呢,因为我没有这方面的经验,我做了一些研究,但仍然没有完全理解。你知道吗


Tags: 项目用户网格游戏棋盘玩家计数器空间
1条回答
网友
1楼 · 发布于 2024-04-20 11:24:55

你首先应该考虑的是如何将你的游戏逻辑从你的绘图逻辑中分离出来,以及在考虑如何绘制一个10*10的网格之前如何表示你的游戏状态。你知道吗

这实际上是最重要的事情之一,所以让我重复一遍:首先考虑如何表示你的游戏状态,然后再考虑如何绘制它。你知道吗

假设我们有一个由10个图块组成的板(为了保持这个示例的简单性),那么让我们从创建一个连接这些图块的地图开始:

CONNECTIONS = {
    2: 4,
    1: 7,
    5: 3,
    8: 0,
}

这意味着如果一个玩家在地砖2上着陆,他们将移动到地砖4。如果它们落在8号牌上,它们会移回0,等等。所以CONNECTIONS已经是游戏的重要部分了。你知道吗

既然我们想要一个好的棋盘,让我们定义每个磁贴在屏幕上的位置。我们可以使用一个简单的列表:

POSITIONS = [
    (93, 394),
    (244, 338),
    (368, 391),
    (457, 317),
    (579, 348),
    (572, 181),
    (458, 108),
    (379, 203),
    (231, 115),
    (89, 197)
]

这意味着tile 0位于屏幕位置(93, 394)等,并且已经允许我们使用pygame的draw模块绘制一个漂亮的游戏板

screen = pygame.display.set_mode((width, height))
...
# Let's create a board
board = screen.copy()
board.fill((40, 40, 40))

# We connect all dots with lines
prev = None
for pos in POSITIONS:
    if prev:
        pygame.draw.line(board, (0,0,0), prev, pos, 4)
    prev = pos

# Then we draw the good and bad connections
for pos in CONNECTIONS:
    target = CONNECTIONS[pos]
    pygame.draw.line(board, (0,200,0) if pos < target else (200,0,0), POSITIONS[pos], POSITIONS[target], 4)

# Last we create all fields
for pos in POSITIONS:
    pygame.draw.circle(board, (0,0,0), pos, 40)
    pygame.draw.circle(board, (200,200,200), pos, 36)

enter image description here

然后再重用CONNECTIONSPOSITIONS(绿色是好的,红色是坏的)。你知道吗

当然,如果你想要一个简单的网格而不是一个不对称的电路板,你可以使用一个嵌套的循环或者一些简单的数学来动态地创建每个图块的位置。你知道吗

但是正如你所看到的,我们已经在游戏坐标(1D:棋盘是线性的)和屏幕坐标(2D:x和y)之间有了某种关系,这些东西是不同的。你知道吗

这意味着如果我们使用一些数据结构来表示玩家,那么这个数据结构(我们将使用pygame的Sprite的子类)也应该有两个位置:一个代表玩家在棋盘上的位置,另一个代表精灵在场地上的位置。你知道吗

当玩家移动时,我们改变它的棋盘位置,如果他们落在一个有连接的场地上(我们将他们的棋盘位置与CONNECTIONS中的值进行比较),我们就知道玩家必须继续移动。你知道吗

所以这里有一个我一起破解的例子(按任意键滚动模具并移动):

import pygame
import random

CONNECTIONS = {
    2: 4,
    1: 7,
    5: 3,
    8: 0,
}

POSITIONS = [
    (93, 394),
    (244, 338),
    (368, 391),
    (457, 317),
    (579, 348),
    (572, 181),
    (458, 108),
    (379, 203),
    (231, 115),
    (89, 197)
]

class Player(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.Surface((30, 50))
        self.image.fill((200,100,0))
        self.rect = self.image.get_rect()

        # The player has a state.
        # Either it is WAITING, so it reacts to the move() command
        # Or it is already MOVING, and pressing a key does nothing
        self.state = 'WAITING'

        # It's important to have a distinction between the logical position
        # on the board, and the actual position of the sprite on the screen
        # We start on board position 0
        self.board_pos = 0

        # We set the current position of the sprite to the position
        # of the tile we're standing on
        self.rect.center = POSITIONS[self.board_pos]

        # We use an additional vector to store the position of the
        # sprite so we can let pygame handle all the vector math
        self.pos = pygame.Vector2(self.rect.center)

    def move(self):
        if self.state == 'WAITING':
            # If we are waiting and a key is pressed, we start moving
            eyes = random.randint(1, 6)
            print(f"rolled a {eyes}")
            # Keep track of how many tiles we move forward
            self.eyes = eyes
            self.state = 'MOVING'
            # Since we move forward, increase our board position
            self.board_pos += 1
            # We want a smooth movement, so we store the position
            # of the next tile in a vector, too
            self.target = pygame.Vector2(POSITIONS[self.board_pos])

    def update(self, dt, events):
        if self.state == 'MOVING':
            # When we're moving, create a movement vector 
            # so we know in which direction we have to move
            movement = self.target - self.pos
            length = movement.length()

            if length < 5:
                # We arrived at out target tile

                # If we still have some tiles to go, decrease the number
                # since we arrived at one
                if self.eyes > 0:
                    self.eyes -= 1

                self.pos = self.target
                if self.eyes == 0:
                    # We moved all tiles, so let's see if there's a 
                    # connection to another tile
                    con = CONNECTIONS.get(self.board_pos, None)
                    if con:
                        # If there is, we have a new target to move to 
                        self.board_pos = con
                        self.target = pygame.Vector2(POSITIONS[self.board_pos])
                    else:
                        # If not, our turn is over
                        self.state = 'WAITING'
                else:
                    # We have still some tiles to go
                    self.board_pos += 1
                    self.target = pygame.Vector2(POSITIONS[self.board_pos])
            else:
                # Just keep moving
                movement.normalize_ip()
                # Some math to keep the movement smooth and nice
                self.pos += movement * dt/10 * max(length/40., 0.7)

        # Pygame uses the rect attribute to position the sprite
        # so let's update it with the position of our vector
        self.rect.center = int(self.pos.x), int(self.pos.y)

def main():
    width, height = 640, 480
    pygame.init()
    screen = pygame.display.set_mode((width, height))
    clock = pygame.time.Clock()
    player = Player()
    sprites = pygame.sprite.Group(player)

    # Let's create a board
    board = screen.copy()
    board.fill((40, 40, 40))

    # We connect all dots with lines
    prev = None
    for pos in POSITIONS:
        if prev:
            pygame.draw.line(board, (0,0,0), prev, pos, 4)
        prev = pos

    # Then we draw the good and bad connections
    for pos in CONNECTIONS:
        target = CONNECTIONS[pos]
        pygame.draw.line(board, (0,200,0) if pos < target else (200,0,0), POSITIONS[pos], POSITIONS[target], 4)

    # Last we create all fields
    for pos in POSITIONS:
        pygame.draw.circle(board, (0,0,0), pos, 40)
        pygame.draw.circle(board, (200,200,200), pos, 36)

    dt = 0
    while True:
        events = pygame.event.get()
        for e in events:
            if e.type == pygame.QUIT:
                return
            if e.type == pygame.KEYDOWN:
                player.move()

        screen.blit(board, (0,0))
        sprites.update(dt, events)
        sprites.draw(screen)
        pygame.display.flip()
        dt = clock.tick(60)

if __name__ == '__main__':
    main()

enter image description here

相关问题 更多 >