Como fiz um jogo para o Bloco de Notas



Ao ler sobre soluções incomuns de desenvolvedores independentes, me deparei com o ouro. Aqui está um artigo sobre o jogo em um editor de texto. Arte, animação, enredo - tudo está como deveria ser.

Eu criei o jogo E ainda assim dói ( talvez o autor queira dizer que dói, mas eu poderia usar essa opção de propósito - aprox. ).


O projeto pode ser baixado aqui e o código pode ser visualizado no Github .

Tudo começou em 2017 com a pergunta: "É possível criar um jogo no bloco de notas?" Então eu apenas sorri. Três anos se passaram. Depois de pensar em como tudo vai funcionar e ter certeza de que é real, decidi fazer este jogo.

Normalmente você pressiona um botão e algo acontece no jogo. Aperte A e Mario pula. Tudo está ligado ao recebimento de informações e feedback. O jogo recebe informações e exibe suas próprias.

No jogo para o Bloco de notas, haverá alterações na entrada que o usuário faz no arquivo e na saída, alterações que o jogo faz no arquivo. Para fazer isso, o aplicativo rastreia a última vez que o arquivo foi salvo. Se ele mudou, o jogo lê o conteúdo do arquivo e introduz novos dados nele.

Há um problema: o bloco de notas da Microsoft não verifica se o arquivo foi modificado. Eu teria que salvar o arquivo, fechar e abri-lo novamente. Criar esse jogo é possível, mas não parece muito divertido. Eu tive que procurar uma alternativa.

Entendo sua decepção devido ao fato de o jogo, como resultado, não ter sido feito no habitual Bloco de Notas. Meu título pode ser executado nele - apenas um processo um pouco confuso. Decidi sacrificar a frieza do projeto para tornar o jogo mais agradável.



Alternativa


Eu tive que procurar outro editor de texto. O único requisito era a atualização automática de arquivos. Embora um pouco mais tarde você verá que eu usei outro recurso.

Primeiro, o Notepad ++ e o Sublime Text vieram à mente. Mas eles nem parecem o bloco de notas na aparência; o charme do projeto teria desaparecido completamente. Além disso, eles perguntam ao jogador se ele gostaria de atualizar o arquivo. Isso é muito melhor do que fechar e abrir um arquivo, mas ainda assim distrai a jogabilidade. Eu queria que o arquivo fosse atualizado automaticamente. Então o Notepad2 chamou minha atenção. Ele era quase perfeito.

O editor pode ser configurado para se parecer com o MS Notepad e, o mais importante - ele verifica as alterações feitas no arquivo. Mas, assim como o Notepad ++ e o Sublime Text, o Notepad2 pergunta ao player se o arquivo precisa ser alterado. Felizmente, o editor tem código-fonte aberto e eu poderia aperfeiçoá-lo com perfeição.



O Notepad2 está escrito em C. Estou um pouco familiarizado com esse idioma, mesmo que não possa ser chamado de especialista. Um programador Javascript experiente poderá ler e entender a essência geral do código, mas não foi tão fácil entender o código-fonte do Notepad2 para fazer as alterações necessárias.

Para começar, decidi procurar texto na caixa de diálogo: “O arquivo foi modificado por um programa externo. Recarregar o arquivo? ". Este é o valor da variável usada como argumento na função da caixa de diálogo. E eu a encontrei.

if ((iFileWatchingMode == 2 && !bModified && iEncoding == iOriginalEncoding) ||
        MsgBox(MBYESNO,IDS_FILECHANGENOTIFY) == IDYES) {

Este código verifica se o conteúdo do arquivo foi alterado. Se ele mudou, uma janela é aberta e o programa verifica se o usuário escolheu "Sim". Eu só precisava substituir uma peça

MsgBox(MBYESNO,IDS_FILECHANGENOTIFY) == IDYES

TRUE e o programa começou a atualizar automaticamente o arquivo. Então, eu criei uma renderização baseada em ASCII. Resta criar um mecanismo adequado.

Desenhando


O jogo é feito com amor: LÖVE é uma estrutura de código aberto para jogos 2D escritos em Lua. Eu usei essa plataforma por muitos anos e até montei um tutorial . Para este projeto, o módulo LÖVE do sistema de arquivos foi usado principalmente porque fornece todos os recursos necessários. Normalmente, o LÖVE cria uma imagem que é exibida na tela.

Eu precisava quase da mesma coisa: a saída da arte ASCII em um arquivo de texto. Comecei com uma casa e um pássaro, e o pássaro deveria voar através de um arquivo. Peguei a arte que encontrei no ASCII Art , mas apenas trabalhos originais são usados ​​no jogo (exceto fontes).



E:



Baixar arte é apenas ler um arquivo.

house = love.filesystem.read("art_house.txt")
bird = love.filesystem.read("art_bird.txt")

A casa é usada como pano de fundo, então comecei desenhando esta imagem na “tela”. A tela neste caso é home.txt.

love.filesystem.write("home.txt", house)

Eu queria que o pássaro funcionasse dessa maneira:

local x, y = 20, 40
drawArt(bird, x, y)

x é o número da coluna, y é o número da linha. Portanto, ele quebrou a tela e o pássaro em listas de linhas.

-- Get the current canvas
screen = love.filesystem.read("home.txt")

-- Create a table. A table is like an array.
screen_lines = {}

-- The lua pattern (.-)\n says capture everything until the \n (newline).
-- We add an \n to the end of the file so that it captures the last line as well.
for line in (screen .. "\n"):gmatch("(.-)\n") do
    table.insert(screen_lines, line)
end

Com o pássaro fez o mesmo. Agora, o código que descreve o pássaro deveria se sobrepor ao código da casa. Aqui está o que eu precisava:

  1. Encontre a linha na qual o pássaro deve ser desenhado.
  2. Imprima a linha inteira em x.
  3. Imprima o restante da linha, começando com x + o comprimento da arte com o pássaro.
  4. Crie uma nova linha com a primeira parte, o pássaro e a parte restante.
  5. Repita o mesmo para todas as outras linhas.

No código, fica assim:

function drawArt(art, x, y)
    art_lines = getLines(art)

    -- In Lua, you can get the length of a table and string with #
    for i=1, #screen_lines do
        if i == y then
            for j=1 ,#art_lines do
                -- With string:sub(start, end) we can get part of a string
                local first_part = screen_lines[i]:sub(1, x - 1)
                local second_part = screen_lines[i]
                                    :sub(x + #art_lines[j], #screen_lines[i])
                screen_lines[i] = first_part .. art_lines[i] .. second_part
            end
        end
    end
end

O que aconteceu:



Provavelmente, você notou que o pássaro é um retângulo - os espaços são usados ​​em sua arte. Para corrigir a situação, calculei o número de espaços no início de cada linha e adicionei esse número às coordenadas para que apenas a arte fosse desenhada.

-- (%s) gets all the whitespace characters.
local spaces = art_lines[j]:match("(%s*)")
-- Remove the spaces from the line.
art_lines[i] = art_lines[i]:sub(#spaces + 1, #art_lines[i])
local first_part = screen_lines[i]:sub(1, x + #spaces - 1)
local second_part = screen_lines[i]:sub(x + #spaces + #art_lines[j], #screen_lines[i])
screen_lines[i] = first_part .. art_lines[i] .. second_part

Tornou-se muito melhor:



Animação


Comecei a adicionar mais chips, por exemplo, animação:



todos os quadros estão localizados em um arquivo e separados pela tag {{F}}. A etiqueta é determinada durante a leitura e permite definir a sequência de quadros. Graças a isso, temos uma animação clássica. Crie um cronômetro e desenhe quadros de acordo com ele.

{{F}}
_   _ 
 'v'
{{F}}
      
--v--
{{F}}
      
_/v\_

Também implementei a saída do texto impresso e exibi separadamente uma tela, inventário e uma janela para entrar na solução. Houve um problema. Como o jogo sabe que um arquivo foi aberto? Este é o segundo recurso que falei anteriormente.

No código fonte do Notepad2, prescrevi que o arquivo deveria ser salvo imediatamente após a abertura. O jogo então verifica se o último tempo de economia foi alterado. Então ela descobre que o arquivo estava aberto e pode alterá-lo.

// At the end of the FileLoad function.
// If the file is not new, and the file has not been reloaded, save it.
if (!bNew && !bReload) {
    FileSave(TRUE,FALSE,FALSE,FALSE);
}

Como resultado, recebi uma estrutura na qual você pode trabalhar. É hora de criar um jogo.

Durante nove dias de desenvolvimento (a julgar pela data em que os arquivos gif foram criados), fiz o seguinte:



Se você executou o jogo, sabe que ele não possui texto ou animação imprimível. Havia várias razões para isso:

  • , HDD/SSD . . , .
  • . , , . , .
  • — , . . . , , -, . . , , . , , , — .


Fiquei furioso porque o usuário teve que arrastar o arquivo para a janela do Notepad2 para iniciar o jogo. Ao clicar duas vezes no arquivo, o Bloco de notas ou outro programa padrão para leitura de .txt foi aberto. Era possível registrar um comando que alterava o aplicativo para esses arquivos no Notepad2, mas eu pessoalmente não gostaria que algum tipo de jogo parecesse tão falso no meu computador.

Talvez retorne as configurações originais quando você fechar o jogo? É possível, mas haverá um problema se o jogo travar ou fechar inesperadamente.

Todas as decisões pareciam insuficientemente fundamentadas até que eu percebi que, em vez dos arquivos .txt habituais com outro "x", poderia ser usado. Para ser mais preciso, o caractere Unicode é U + 0445 (letra minúscula cirílica Ha). Para não ficar confuso, chamei o arquivo de * .tXt. Como resultado, todos os arquivos do jogo estavam com resolução * .tXt e, por padrão, abertos no Bloco de Notas2.

assoc .tXt=tXt
ftype tXt=[directory]/.notepad/Notepad2.exe "%1"

O programa padrão pode ser atribuído apenas como administrador. Se você abrir o jogo em uma conta diferente, serão usados ​​arquivos txt. Se você abrir o arquivo no bloco de notas normal, o jogo informará que você precisa arrastar o arquivo para a janela aberta do bloco de notas. Ou execute-o como administrador para que seja aberto clicando duas vezes.

Motivação


De fato, tudo foi feito há três anos. O que eu fiz o resto do tempo? Um exemplo clássico de falta de motivação.

Inicialmente, o enredo era um pouco mais longo do que agora. O dragão matou seus pais, você tem que ir ao ferreiro Ferdan, então ele forjou uma espada. Pensa-se que a espada é feita de três materiais que precisam ser coletados. Isso aumentou muito o volume do jogo e empurrou o fim do desenvolvimento. O jogo não foi muito divertido e eu abandonei o projeto dois meses depois.

Mas eu mantive isso na minha cabeça o tempo todo. Eu depurei uma estrutura inteira que me permitiu criar um jogo no Bloco de Notas, e o projeto não saiu do papel. Era necessário terminar. Em 2019, eu não concluí quase nenhum projeto. A decepção me levou a decidir: terminar o inacabado em 2020.

E aqui está ela. Reduzi a trama, me dei um mês por tudo (ficou mais uma semana) e corri para a batalha. Ainda solicitou um labirinto. Prêmios, respectivamente, o prazo estava marcado para 2 de fevereiro. Então havia motivação.

Conclusão


Estou feliz por ter completado o jogo. É incrível quanto tempo o projeto acabou de coletar poeira digital, mas no final, um mês foi suficiente. O jogo não deveria ter sido tão volumoso quanto eu queria a princípio - um projeto fora do padrão deve mostrar apenas os recursos que podem ser implementados nele.

Qual é o próximo? Um jogo de tinta? Jogo na calculadora? É improvável que eu os faça. Mas gosto de pensar em jogos que usam plataformas não tradicionais.

All Articles