我如何为记事本制作游戏



在阅读来自独立开发人员的不寻常解决方案时,我遇到了金。这是一篇有关文本编辑器中游戏的文章。艺术,动画,情节-一切都应如此。

我创建了游戏,但是很伤人(也许作者想说很伤人,但是我可以故意使用此选项-大约)。


该项目可以在这里下载,并在Github上查看代码

一切始于2017年,当时的问题是:“是否可以在记事本中制作游戏?”然后我只是笑了。三年过去了。在考虑了一切将如何工作并确保它是真实的之后,我决定制作这款游戏​​。

通常,您按下一个按钮,游戏中就会发生某些事情。命中A,马里奥跳起来。一切都与接收信息和反馈紧密相关。游戏接收输入并显示自己的输入。

在记事本游戏中,用户对文件的输入将发生更改,而输出中游戏对文件的更改将发生更改。为此,应用程序会跟踪文件的上次保存时间。如果已更改,则游戏会读取文件的内容并将新数据引入文件中。

有一个问题:Microsoft的记事本不会检查文件是否已被修改。我将不得不保存文件,关闭并再次打开它。可以制作这样的游戏,但是听起来并不有趣。我不得不寻找替代方案。

我能理解您的失望,因为游戏结果不是在通常的记事本中制作的。我的标题可以在其中运行-只是一个有点混乱的过程。我决定牺牲项目的凉爽度,以使游戏更加有趣。



另类


我不得不寻找另一个文本编辑器。唯一的要求是自动文件更新。虽然过了一会儿,您将看到我使用了另一个功能。

首先,想到了记事本++和Sublime Text。但是它们在外观上根本不像记事本;该项目的魅力将完全消失。另外,他们询问播放器他是否要更新文件。这比关闭和打开文件好得多,但仍会分散游戏玩法。我希望文件自动更新。然后记事本2引起了我的注意。他几乎是完美的。

可以将编辑器配置为看起来像MS记事本,最重要的是-它检查对文件所做的更改。但是就像记事本++和Sublime Text一样,记事本2会询问播放器是否需要更改文件。幸运的是,编辑器具有开源代码,我可以完善它。



Notepad2用C编写。即使我不能被称为专家,我对这种语言还是有点熟悉。经验丰富的Javascript程序员将能够阅读和理解代码的一般本质,但是要进行必要的更改,要理解Notepad2的源代码并不容易。

首先,我决定从对话框中搜索文本:“文件已由外部程序修改。重新加载文件?”。这是用作对话框函数中的参数的变量的值。我找到了她。

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

此代码检查文件的内容是否已更改。如果已更改,则将打开一个窗口,程序将检查用户是否选择了“是”。我只需要更换一块

MsgBox(MBYESNO,IDS_FILECHANGENOTIFY) == IDYES

设置为TRUE,程序开始自动更新文件。因此,我创建了一个基于ASCII的呈现器。剩下的就是创建一个合适的引擎。

画画


游戏是用爱创造的LÖVE是用Lua编写的2D游戏的开源框架。我使用这个平台很多年,甚至编写了一个教程。在此项目中,主要使用文件系统的LÖVE模块,因为它提供了所有必需的功能。通常,LÖVE创建图像,然后将其显示在屏幕上。

我需要几乎相同的东西:文本文件中ASCII艺术作品的输出。我从一间房子和一只鸟开始,那只鸟应该飞过一个文件。我采用了在ASCII Art上发现的艺术品,但游戏中仅使用了原创作品(字体除外)。



并且:



下载艺术作品只是读取文件。

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

该房子被用作背景,因此我首先在“屏幕”上绘制此图像。在这种情况下,屏幕为home.txt。

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

我希望这只鸟以这种方式工作:

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

x是列号,y是行号。因此,他将屏幕和小鸟分成几行。

-- 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

与那只鸟一样。现在,描述鸟类的代码应该与房屋代码重叠。这是我需要的:

  1. 找到应该画鸟的线。
  2. 将整行打印到x。
  3. 打印其余的行,从x +鸟的艺术长度开始。
  4. 用第一部分,鸟和其余部分创建新行。
  5. 对所有其他行重复相同的步骤。

在代码中,它看起来像这样:

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

发生的事情:



您可能注意到这只鸟是一个矩形-在其艺术中使用了空格。为了纠正这种情况,我计算了每行开头的空格数,并将此数字添加到坐标中,以便仅绘制艺术作品。

-- (%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

它变得更好了:



动画


我开始添加更多的筹码,例如动画:



所有帧都位于一个文件中,并用{{F}}标签隔开。标签在读取过程中确定,并允许您设置帧的顺序。因此,我们得到了经典的动画。创建一个计时器,并根据它绘制框架。

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

我还实现了打印文本的输出,并分别显示了屏幕,清单和用于输入解决方案的窗口。有一个问题。游戏如何知道已打开文件?这是我之前谈到的第二个功能。

在Notepad2的源代码中,我规定打开后应立即保存该文件。然后,游戏检查以查看上次保存时间是否已更改。因此她发现该文件已打开,可以对其进行更改。

// 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);
}

结果,我得到了一个可以在其中工作的框架。现在该创建游戏了。

经过九天的开发(从创建gif文件的日期来看),我做到了:



如果您运行了游戏,则您知道它没有可打印的文本或动画。这有几个原因:

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


我很生气,用户必须将文件拖到Notepad2窗口中才能开始游戏。通过双击文件,打开记事本或其他默认程序以读取.txt。可以在Notepad2上注册用于更改此类文件的应用程序的命令,但是如果某种游戏在我的计算机上如此伪装,我个人不希望这样做。

也许在关闭游戏时返回原始设置?可能,但是如果游戏崩溃或意外关闭,将会出现问题。

直到我意识到可以使用带有另一个“ x”的常规.txt文件代替之前,所有决定似乎都没有得到充分证实。确切地说,Unicode字符是U + 0445(西里尔小写字母Ha)。为了不引起混淆,我将文件命名为* .tXt。结果,所有游戏文件的分辨率均为* .tXt,默认情况下在Notepad2中打开。

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

默认程序只能分配为管理员。如果您使用其他帐户打开游戏,将使用txt文件。如果您在常规记事本中打开文件,游戏会通知您需要将文件拖到打开的记事本窗口中。或者以管理员身份运行它,以便双击打开它。

动机


实际上,一切都在三年前完成。其余时间我做了什么?缺乏动力的经典例子。

最初,该地块比现在更长。龙杀死了你的父母,你必须去找铁匠费丹,所以他锻造了剑。人们认为剑是由三种需要收集的材料制成的。这极大地增加了游戏的数量并推动了开发的结束。游戏不是很有趣,两个月后我放弃了这个项目。

但是我一直把它放在脑海中。我调试了整个框架,使我可以在记事本中创建游戏,但该项目并未开展。有必要完成它。在2019年,我几乎没有完成任何项目。失望促使我决定:在2020年完成未完成的工作。

她在这里。我缩短了情节,给了自己一个月的时间(事实证明,结果延长了一周),然后冲上了战斗。仍在申请迷宫。奖项的截止日期分别定于2月2日。因此就有了动力。

结论


我很高兴我完成了比赛。该项目收集数字灰尘多长时间令人惊讶,但最后一个月就足够了。最初,游戏本来就不应该像我想的那样庞大-这样的非标准项目应该只显示可以在其中实现的功能。

下一步是什么?油漆游戏?游戏中的计算器?我不太可能做。但是我喜欢考虑使用非传统平台的游戏。

All Articles