Начертайте Ascii символ над правоъгълника с pygame

Опитвам се да направя измамник като използвайки pygame.

въведете описание на изображението тук

Всъщност нямам проблем да начертая първата мрежа, която представлява фона на играта (използвайки mapLoaded, които съдържат оригиналната карта и drawMap() функция, която връща списък с Case обект).

Обичам правоъгълника, но за в бъдеще искам да нарисувам върху този правоъгълник ascii символа, съхранен в Case обект.

Използвайки този метод за замяна на rect by char, мога да създам по-късно Object като играч "@", който също се изчертава върху този фонов правоъгълник или знак.

над правоъгълника

Въпросът ми е свързан с това изображение, как мога да начертая (и по-късно да преместя) 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 тук:

Файл1

Файл2


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
Можете да изчислите необходимия размер на шрифта, като използвате Шрифт. размер. След като изобразите текста, той е обикновен Surface и Rect, който можете да рисувате както обикновено.   -  person ninMonkey    schedule 23.09.2013
comment
Благодаря за коментара, отварям награда за motivated, защото мисля, че това е добър въпрос за начинаещи в pygame Api.   -  person reyman64    schedule 25.09.2013
comment
@Veedrac Rogue-likes традиционно се правят с помощта на ASCII знаци. Това е част от обжалването.   -  person    schedule 27.09.2013
comment
Коригирам липсващия код и добавям python файлове за любопитни и помощници :)   -  person reyman64    schedule 27.09.2013
comment
Без връзка, обмислете използването на libtcod за пълна библиотека за разработка на RL   -  person TankorSmash    schedule 27.09.2013
comment

Трябва да създам някои потребителски броячи на производителност в моята инсталационна програма. Моят инсталатор е направен с Inno Setup (това не може да се промени в момента).

В c# мога да създам броячите с помощта на PerformanceCounterCategory.Create (https://msdn.microsoft.com/en-us/library/5e3s61wf%28v=vs.90%29.aspx)

System.Diagnostics.PerformanceCounterCategory.Create(
        "Multi Counter Category", "Category help",
        PerformanceCounterCategoryType.SingleInstance, CounterDatas);

Но не мога да намеря нищо за създаването им чрез Inno Setup. Всякакви примери или документация как да направите това.

благодаря Скот

  -  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