Нарисуйте символ Ascii над прямоугольником с помощью pygame

Я пытаюсь сделать мошенника, например, с помощью pygame.

введите описание изображения здесь

На самом деле у меня нет проблем с рисованием первой сетки, которая представляет собой фон игры (используя mapLoaded, который содержит исходную карту и drawMap() функцию, которая возвращает список Case Object).

Мне нравится прямоугольник, но в будущем я хочу нарисовать поверх этого прямоугольника символ ascii, хранящийся в объекте Case.

Используя этот метод для замены прямоугольника на символ, я могу позже создать Object, например player «@», который также будет рисовать поверх этого фонового прямоугольника или символа.

над прямоугольником

Мой вопрос связан с этим изображением, как я могу нарисовать (а затем переместить) символ ascii (здесь игрок @) в верхнем центре функции pygame.draw.rect(), используемой для рисования каждой ячейки фона (с использованием атрибута символа, определенного в 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


person reyman64    schedule 23.09.2013    source источник
comment
Не могли бы вы подробнее объяснить, в чем заключается ваш конкретный вопрос?   -  person Shashank    schedule 23.09.2013
comment
Надеюсь, теперь это стало более ясным.   -  person reyman64    schedule 23.09.2013
comment
Я очень рекомендую использовать изображения вместо текста: текст зависит от установленных шрифтов и размеров и поэтому ненадежен. Сделайте несколько изображений всех желаемых персонажей и используйте их.   -  person Veedrac    schedule 23.09.2013
comment
Я читал, что pygame создает изображение из шрифта, невозможно сгенерировать изображение ascii размера моего случая вместо создания всех символов ascii вручную в png или другом?   -  person reyman64    schedule 23.09.2013
comment
Это так, но я не думаю, что это лучший способ. Посмотрите на pygame.font.Font, если вы ' мы намерены сделать это таким образом.   -  person Veedrac    schedule 23.09.2013
comment
Вы можете рассчитать необходимый размер шрифта с помощью Font. размер. После рендеринга текста это обычная поверхность и прямоугольник, которые можно рисовать как обычно.   -  person ninMonkey    schedule 23.09.2013
comment
Спасибо за комментарий, я открываю награду для мотивированных, потому что я думаю, что это хороший вопрос для новичков в pygame Api.   -  person reyman64    schedule 25.09.2013
comment
@Veedrac Rogue-like традиционно создаются с использованием символов ASCII. Его часть обращения.   -  person    schedule 27.09.2013
comment
Исправляю недостающий код и добавляю файлы python для любопытных и помощников :)   -  person reyman64    schedule 27.09.2013
comment
Несвязанный, рассмотрите возможность использования libtcod для полной библиотеки разработки RL   -  person TankorSmash    schedule 27.09.2013
comment
@LegoStormtroopr Я согласен, я просто думаю, что у вас должны быть изображения of символов ASCII, потому что рендеринг шрифтов - это хлопот.   -  person Veedrac    schedule 28.09.2013


Ответы (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. Это обычный Surface, созданный pygame.font.Font при инициализации программы.

Глобальные переменные можно переопределить, чтобы изменить макет, цвет, размеры и т. Д. Существует также загружаемая версия примера.

person 0eggxactly    schedule 01.10.2013
comment
Спасибо за этот замечательный и подробный ответ :) Еще один вопрос. Как вы думаете, можно ли использовать функцию fit для изменения размера Rect, возвращаемого функцией font.get_rect ()? - person reyman64; 02.10.2013
comment
Метод surface.get_rect получает прямоугольник символа. Этот прямоугольник является обычным и может быть изменен на rect.fit. Нет font.get_rect. Модуль шрифта в основном содержит методы, указывающие pygame, как визуализировать поверхность. Как только шрифт отображает поверхность, он идентичен любому другому (например, тот, который вы получите при загрузке изображения). - person 0eggxactly; 02.10.2013
comment
Итак, если я понимаю, чтобы избежать проблемы, вызванной определением размера шрифта / плеера, можно принудительно изменить размер поверхности, которая содержит прямоугольник шрифта, чтобы получить заданную и фиксированную ширину / высоту, определенную для размера ячейки. - person reyman64; 03.10.2013
comment
Конечно, но, вероятно, в этом нет необходимости. Есть две лучшие альтернативы. Первый - создать промежуточную поверхность фиксированного размера, на которую вы переносите рендеринг шрифта. Второй - изменить размер прямоугольника поверхности рендеринга шрифта без изменения размера самой поверхности. Собственно, зачем вообще его менять? В игре на основе сетки координаты ячеек - это все, что вам нужно. - person 0eggxactly; 04.10.2013
comment
Шум, потому что размер рендеринга шрифта не соответствует размеру ячейки (поверхность шрифта возвращает что-то вроде 7 * 9, а ячейка прямоугольная, как 9 * 9), поэтому мне нужно переустановить; Я поясню суть на примере: gist.github.com/reyman/6839004 - person reyman64; 05.10.2013