【问题标题】:Draw Ascii character above rectangle with pygame用pygame在矩形上方绘制Ascii字符
【发布时间】:2013-09-28 00:26:22
【问题描述】:

我正在尝试用pygame制作一个流氓。

实际上,我可以毫无问题地绘制代表游戏背景的第一个网格(使用包含原始地图的mapLoaded 和返回Case 对象列表的drawMap() 函数)。

我喜欢矩形,但为了将来我想在这个矩形上绘制存储到 Case 对象中的 ascii 字符。

使用此方法通过 char 覆盖 rect,我可以稍后创建 Object,例如播放器“@”,它也在此背景矩形或字符的顶部绘制。

我的问题与这张图片有关,我如何在用于绘制背景的每个单元格的 pygame.draw.rect() 函数的顶部中心绘制(然后移动)一个 ascii 字符(这里是播放器 @)(使用Case 中定义的字符属性。

我的初始化代码:

import os
import drawRogue as draw

mapLoaded = [[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
             [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1],
             [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1],
             [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,0,0,1,1,1,1,1,1,1,1],
             [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,0,1,1,1,1,1,1,1,1],
             [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,0,0,0,1,1,1,1,1,1,1],
             [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1],
             [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,0,0,0,0,1,1,1,1,1],
             [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1],
             [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,1],
             [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1],
             [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1],
             [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1],
             [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1],
             [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,0,0,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1],
             [1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1],
             [1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
             [1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
             [1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1],
             [1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1],
             [1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,0,0,0,1,1,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1],
             [1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1],
             [1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1],
             [1,1,1,1,1,1,1,1,1,1,0,0,0,1,0,0,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1],
             [1,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,0,1,1,1,1,1,0,0,0,0,0,0,1,1,1,0,0,1,0,0,0,1,1,1,1,1],
             [1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1,1,1],
             [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1],
             [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,1,1,1,1],
             [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1],
             [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1],
             [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1],
             [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1],
             [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1],
             [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1],
             [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1],
             [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1],
             [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
             [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
             [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
             [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
             [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
             [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]]

class Object:
    def __init__(self,x,y,char,color):
        self.x = x
        self.y = y
        self.char = char
        self.color = color

        def move(self,dx,dy):
            if not map[self.x + dx][self.y + dy].blocked:
                self.x = self.x + dx
                self.y = self.y + dy

class Case:
    #a tile of the map and its properties
    def __init__(self, char, blocked):
        self.blocked = blocked
        self.char =  char


#Afficher seulement une partie du monde... tres vaste comme vous le voyez...        
def drawMap(mymap):
    tileMap = []
    for line in mymap:
        tileLine = []
        for value in line:
            if value == 1:
                tileLine.append(Case("#",False))
            else:
                tileLine.append(Case(".",True))
        tileMap.append(tileLine)
    return tileMap

clear = lambda: os.system('clear')

if __name__ == "__main__":

    clear()
    tileMap = drawMap(mapLoaded)
    draw.drawInit()
    draw.addColorRules("#",(255,255,255))
    draw.addColorRules(".",(0,0,0))
    draw.drawScreen(tileMap,40)
    while True:
        draw.drawScreen(tileMap, 40)
        draw.events()

我在drawRogue.py 中绘制背景的实际代码:

import sys, pygame

colorRules = {}

def drawInit():
    pygame.init()

def drawScreen(t_view,speed):

    grid_size = grid_rows, grid_cols = len(t_view), len(t_view)
    square_pixels = 15
    base_offset = 30
    size = width, height = (2*base_offset)+(grid_cols*square_pixels), (2*base_offset)+(grid_rows*square_pixels)

    screen = pygame.display.set_mode(size)
    clock = pygame.time.Clock()

    render_steps = True
    screen.fill((0,0,0))

    for event in pygame.event.get():
        if event.type == pygame.QUIT: sys.exit()

    for row in xrange(grid_rows):
        for col in xrange(grid_cols):
            for char in colorRules.keys():
                if (t_view[row][col].char == char):
                    FillSquare(screen, base_offset, square_pixels,(row, col), colorRules[char])

    #draw the outer border
    border_rect = (base_offset, base_offset, (grid_cols*square_pixels), (grid_rows*square_pixels))
    pygame.draw.rect(screen, (150,150,0), border_rect, 2)
    pygame.display.flip()
    clock.tick(speed)

def FillSquare(screen, base_offset, square_pixels, loc, color):
    row = loc[0]
    col = loc[1]
    off_x = base_offset + col * square_pixels
    off_y = base_offset + row * square_pixels
    rect = (off_x+4, off_y+4,  square_pixels - 6, square_pixels - 6)
    pygame.draw.rect(screen, color, rect)

def addColorRules(char, color):
    colorRules[char] = color

def events():
    for event in pygame.event.get():
        if event.type == pygame.QUIT: sys.exit()

您可以在这里下载并测试这两个 python 文件:

File1

File2

【问题讨论】:

  • 您能否详细解释一下您的具体问题是什么?
  • 我希望现在更清楚了。
  • 我非常推荐使用图像而不是文本:文本取决于安装的字体和大小,因此不可靠。为所有想要的角色制作几张图片并使用它们。
  • 您可以使用Font.size 计算所需的字体大小。渲染文本后,它就是一个常规的 Surface 和 Rect,您可以像平常一样绘制。
  • @Veedrac Rogue-likes 传统上是使用 ASCII 字符制作的。这是上诉的一部分。

标签: python drawing pygame game-engine roguelike


【解决方案1】:

如前所述,pygame.font.Font 包含绘制 ASCII 字符的方法。这是一个使用render 在迷宫中绘制角色的示例。

import pygame
from pygame.locals import *

grid = [[0, 0, 0, 0, 0],
        [1, 1, 0, 0, 0],
        [0, 1, 0, 1, 1],
        [0, 1, 0, 1, 0],
        [0, 1, 1, 1, 0]]
resolution = (160, 160)
cell_margin = 14
cell_colors = (255, 255, 255), (0, 0, 0)
player_character = "@"
player_color = (255, 0, 0)
player_size = 20
current_position = [0, 1]

def main():
    pygame.init()
    screen = pygame.display.set_mode(resolution)
    screen.fill(cell_colors[1])
    player = pygame.font.Font(None, player_size).render(player_character,
                                                        False, player_color)
    while True:
        for event in pygame.event.get():
            if event.type == KEYDOWN:
                key = event.key
                if key == K_UP:
                    move(0, -1)
                elif key == K_RIGHT:
                    move(1, 0)
                elif key == K_DOWN:
                    move(0, 1)
                elif key == K_LEFT:
                    move(-1, 0)
            elif event.type == QUIT:
                return
        draw_maze(screen)
        draw_player(player, screen)
        pygame.display.update()

def draw_maze(screen):
    for row in xrange(len(grid)):
        for column in xrange(len(grid[0])):
            screen.fill(cell_colors[grid[column][row]],
                        get_cell_rect((row, column), screen))

def get_cell_rect(coordinates, screen):
    row, column = coordinates
    cell_width = screen.get_width() / len(grid)
    adjusted_width = cell_width - cell_margin
    return pygame.Rect(row * cell_width + cell_margin / 2,
                       column * cell_width + cell_margin / 2,
                       adjusted_width, adjusted_width)

def draw_player(player, screen):
    rect = player.get_rect()
    rect.center = get_cell_rect(current_position, screen).center
    screen.blit(player, rect)

def move(dx, dy):
    x, y = current_position
    nx, ny = x + dx, y + dy
    if nx >= 0 and nx < len(grid) and ny >= 0 and ny < len(grid[0]) and \
       grid[ny][nx]:
        current_position[0] = nx
        current_position[1] = ny

if __name__ == "__main__":
    main()
    pygame.quit()

我试图将示例限制为您有兴趣学习的基本要素。基本上,正在发生的事情是整个网格和角色每帧都被重绘。角色的位置正在被方向键修改。根据get_cell_rect 返回的矩形绘制单元格和字符。字符是pygame.font.Font在程序初始化时创建的普通Surface

可以重新定义全局变量来改变布局、颜色、大小等。还有一个downloadable version的例子。

【讨论】:

  • 感谢这个伟大而详细的答案 :) 只是另一个问题,您认为是否可以使用 fit 函数来调整 font.get_rect() 函数返回的 Rect 的大小?跨度>
  • surface.get_rect 方法获取字符的矩形。该矩形是普通的,可以通过rect.fit 调整大小。没有font.get_rect。 font 模块主要包含告诉 pygame 如何渲染表面的方法。一旦字体呈现表面,它就与任何其他字体相同(例如,您从加载图像中获得的字体)。
  • 所以如果我理解的话,为了避免由字体/播放器大小定义引起的问题,可以强制调整包含字体矩形的表面大小以获得为单元格大小定义的给定和固定宽度/高度.
  • 当然,但这可能是不必要的。有两个更好的选择。第一个是创建一个中间固定大小的表面,您可以将字体渲染到上面。第二种是调整字体渲染表面的矩形大小而不调整表面本身的大小。实际上,为什么您需要调整它的大小?在基于网格的游戏中,您应该只需要单元格坐标。
  • 嗡嗡声,因为字体渲染大小不适合单元格大小(字体表面返回类似 7*9,单元格是矩形,如 9*9),所以我需要重新调整;我在这里举个例子:gist.github.com/reyman/6839004
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多