كيف صنعت لعبة لـ Notepad



أثناء القراءة عن حلول غير عادية من المطورين المستقلين ، صادفت الذهب. هنا مقال عن اللعبة في محرر نصوص. الفن والرسوم المتحركة والمؤامرة - كل شيء كما ينبغي أن يكون.

لقد أنشأت اللعبة ومع ذلك فقد تألمت ( ربما أراد المؤلف أن يقول أنها مؤلمة ، لكن يمكنني استخدام هذا الخيار عن قصد - تقريبًا ).


يمكن تنزيل المشروع هنا ، ويمكن عرض الرمز على Github .

بدأ كل شيء في عام 2017 بالسؤال: "هل من الممكن إنشاء لعبة في المفكرة؟" ثم ابتسمت ابتسامة عريضة. لقد مرت ثلاث سنوات. بعد التفكير في كيفية عمل كل شيء ، والتأكد من أنه حقيقي ، قررت أن أصنع هذه اللعبة.

عادة تضغط على زر ويحدث شيء في اللعبة. ضرب A ، ويقفز ماريو. كل شيء مرتبط بتلقي المعلومات والتعليقات. تتلقى اللعبة المدخلات وتعرض الخاصة بها.

في لعبة Notepad ، ستكون هناك تغييرات في الإدخال الذي يقوم به المستخدم للملف ، وعند الإخراج ، التغييرات التي تجريها اللعبة على الملف. للقيام بذلك ، يتتبع التطبيق آخر مرة تم فيها حفظ الملف. إذا تغيرت ، تقرأ اللعبة محتويات الملف وتقدم بيانات جديدة إليه.

هناك مشكلة: لا يتحقق برنامج Notepad من Microsoft من تعديل الملف. يجب حفظ الملف وإغلاقه وفتحه مرة أخرى. من الممكن إنشاء مثل هذه اللعبة ، لكنها لا تبدو ممتعة للغاية. كان علي أن أبحث عن بديل.

أستطيع أن أفهم خيبة أملك بسبب حقيقة أن اللعبة نتيجة لذلك لم يتم إجراؤها في المفكرة المعتادة. يمكن تشغيل عنواني فيه - مجرد عملية مشوشة قليلاً. قررت أن أضحي ببرودة المشروع لجعل اللعبة أكثر متعة.



لبديل


كان علي أن أبحث عن محرر نص آخر. كان المطلب الوحيد هو التحديث التلقائي للملفات. على الرغم من ذلك بعد قليل ، سترى أنني استخدمت ميزة أخرى.

أولاً ، ظهر في ذهني Notepad ++ و Sublime Text. لكنهم لا يبدون على الإطلاق مثل Notepad في المظهر ؛ فقد كان سحر المشروع قد اختفى تمامًا. بالإضافة إلى ذلك ، يسألون اللاعب عما إذا كان يرغب في تحديث الملف. هذا أفضل بكثير من إغلاق ملف وفتحه ، ولكنه لا يزال يشتت الانتباه عن طريقة اللعب. كنت أرغب في تحديث الملف تلقائيًا. ثم لفتت Notepad2 عيني. كان مثاليًا تقريبًا.

يمكن تكوين المحرر ليبدو مثل MS Notepad ، والأهم من ذلك - أنه يفحص التغييرات التي تم إجراؤها على الملف. ولكن مثل Notepad ++ و Sublime Text ، يسألك Notepad2 اللاعب عما إذا كان الملف بحاجة إلى التغيير. لحسن الحظ ، المحرر لديه كود مفتوح المصدر ، ويمكنني تلميعه إلى الكمال.



تمت كتابة Notepad2 في C. أنا على دراية بهذه اللغة ، حتى إذا لم يكن من الممكن الاتصال بي كخبير. سيتمكن مبرمج جافا سكريبت المتمرس من قراءة وفهم الجوهر العام للكود ، ولكن لم يكن من السهل فهم الكود المصدري لـ Notepad2 لإجراء التغييرات اللازمة.

بادئ ذي بدء ، قررت البحث عن نص من مربع الحوار: "تم تعديل الملف بواسطة برنامج خارجي. هل تريد إعادة تحميل الملف؟ ". هذه هي قيمة المتغير المستخدم كوسيطة في وظيفة مربع الحوار. ووجدتها.

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

يتحقق هذا الرمز لمعرفة ما إذا كانت محتويات الملف قد تغيرت. إذا تغير ، تفتح نافذة ويتحقق البرنامج لمعرفة ما إذا كان المستخدم قد اختار "نعم". كنت بحاجة فقط لاستبدال قطعة

MsgBox(MBYESNO,IDS_FILECHANGENOTIFY) == IDYES

إلى TRUE ، وبدأ البرنامج في تحديث الملف تلقائيًا. لذلك قمت بإنشاء تصيير قائم على ASCII. يبقى إنشاء محرك مناسب.

رسم


اللعبة مصنوعة من الحب: LÖVE عبارة عن إطار عمل مفتوح المصدر للألعاب ثنائية الأبعاد مكتوبة بلغة Lua. لقد استخدمت هذه المنصة لسنوات عديدة وحتى قمت بإعداد برنامج تعليمي . بالنسبة لهذا المشروع ، تم استخدام وحدة 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 ، لكنني شخصياً لا أحبها إذا كان هناك نوع من الألعاب مثل هذا الخداع على جهاز الكمبيوتر الخاص بي.

ربما تعود الإعدادات الأصلية عند إغلاق اللعبة؟ من الممكن ، ولكن ستكون هناك مشكلة إذا تعطلت اللعبة أو أغلقت بشكل غير متوقع.

بدت جميع القرارات غير مدعومة بما يكفي حتى أدركت أنه بدلاً من ملفات .txt المعتادة مع علامة "x" أخرى يمكن استخدامها. على وجه الدقة ، حرف Unicode هو U + 0445 (حروف السيريلية الصغيرة Ha). من أجل عدم الخلط ، سميت الملف * .tXt. نتيجة لذلك ، كانت جميع ملفات اللعبة بدقة * .tXt ، وافتتاحية بشكل افتراضي في Notepad2.

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

يمكن تعيين البرنامج الافتراضي فقط كمسؤول. إذا قمت بفتح اللعبة بحساب مختلف ، فسيتم استخدام ملفات txt. إذا قمت بفتح الملف في برنامج Notepad العادي ، فستخبرك اللعبة أنك بحاجة إلى سحب الملف إلى نافذة Notepad المفتوحة. أو قم بتشغيله كمسؤول حتى يتم فتحه بالنقر المزدوج.

التحفيز


في الواقع ، تم عمل كل شيء قبل ثلاث سنوات. ماذا فعلت بقية الوقت؟ مثال كلاسيكي على نقص الدافع.

في البداية ، كانت المؤامرة أطول قليلاً من الآن. قتل التنين والديك ، عليك أن تذهب إلى الحداد فردان ، لذلك قام بتزوير سيف. كان يعتقد أن السيف مصنوع من ثلاث مواد يجب جمعها. هذا زاد بشكل كبير من حجم اللعبة ودفع نهاية التطوير. لم تكن اللعبة مسلية للغاية ، وتخلت عن المشروع بعد شهرين.

لكني أبقيته في رأسي طوال الوقت. لقد قمت بتصحيح إطار كامل سمح لي بإنشاء لعبة في المفكرة ، ولم يتحرك المشروع بعيدًا عن الأرض. كان من الضروري الانتهاء منه. في عام 2019 ، لم أكمل أي مشروع تقريبًا. دفعتني خيبة الأمل إلى اتخاذ قرار: إنهاء ما لم يكتمل في عام 2020.

وها هي. لقد قمت بتقصير المؤامرة ، وأعطيت نفسي شهرًا لكل شيء (اتضح أنه أسبوع أطول) واندفعت إلى المعركة. لا يزال ينطبق على MAZE. الجوائز ، على التوالي ، كان من المقرر الموعد النهائي في 2 فبراير. لذلك كان هناك دافع.

استنتاج


أنا سعيد لأنني أكملت اللعبة. إنه لأمر مدهش كم من الوقت جمع المشروع الغبار الرقمي ، ولكن في النهاية ، كان الشهر كافيًا. لم يكن يجب أن تكون اللعبة ضخمة كما أردت في البداية - يجب أن يعرض هذا المشروع غير القياسي فقط الميزات التي يمكن تنفيذها فيها.

ماذا بعد؟ لعبة الطلاء؟ اللعبة في الآلة الحاسبة؟ من غير المحتمل أن أصنعها. لكني أحب التفكير في الألعاب التي تستخدم منصات غير تقليدية.

All Articles