يواصل سكوت تيرنر العمل على لعبته التي تم إنشاؤها من الناحية الإجرائية وقرر الآن معالجة مشكلة تصميم حدود الخرائط. للقيام بذلك ، يتعين عليه حل العديد من المشاكل الصعبة وحتى إنشاء لغته الخاصة لوصف الحدود.ظلت الحدود عنصرًا مهمًا في بطاقات الخيال ، والتي كانت على قائمتي لبعض الوقت. عادة ما يكون للخرائط الوظيفية
خط حد بسيط ، لكن الخرائط الخيالية والخرائط التي تعود إلى القرون الوسطى ، والتي غالباً ما يستعيرها الأفكار ، لها حدود مدروسة وفنية إلى حد ما. توضح هذه الحدود أن الخريطة مصنوعة بشكل رائع عن عمد ، وتمنح المشاهد إحساسًا بالتعجب.
يوجد حاليًا طريقتان
بسيطتان لرسم الحدود في لعبة
Dragons Abound . يمكنها رسم خط مفرد أو مزدوج حول محيط الخريطة وإضافة عناصر بسيطة في الزوايا ، كما في هذه الأشكال:
يمكن أن تضيف اللعبة أيضًا حقلًا في أسفل الحدود لاسم الخريطة. هناك العديد من الاختلافات في هذا الحقل في
Dragons Abound ، بما في ذلك العناصر المعقدة مثل رؤوس لولبية وهمية:
هناك تباين في حقول الاسم هذه ، لكن يتم إنشاؤها جميعًا يدويًا.
جانب واحد مثير للاهتمام من حدود بطاقات الخيال هو أنها كلاهما الإبداعي والقالب. غالبًا ما تتكون من عدد صغير من العناصر البسيطة التي تتحد بطرق مختلفة لإنشاء نتيجة فريدة. كالمعتاد ، فإن الخطوة الأولى عند العمل مع موضوع جديد بالنسبة لي هي دراسة مجموعة من أمثلة الخرائط ، وإنشاء فهرس لأنواع عناصر الحدود ، ودراسة مظهرها.
أبسط الحدود عبارة عن سطر واحد يمتد على حواف الخريطة ويشير إلى حدوده. كما قلت أعلاه ، يطلق عليه أيضًا "خط الإطار":
هناك أيضًا اختلاف في موقع الحدود داخل الخريطة. في هذا الإصدار ، تصل الخريطة إلى حواف الصورة ، لكن الحدود تنشئ حدًا افتراضيًا داخل الصورة:
يمكن القيام بذلك مع أي نوع من الحدود ، لكنه عادة ما يستخدم فقط مع حدود بسيطة مثل حدود الإطار.
يتمثل مفهوم تصميم بطاقة الخيال الشائع في المحاكاة كما لو كانت مرسومة على الرق القديم الممزق. في بعض الأحيان يتحقق هذا من خلال رسم الحدود كحافة خشنة للورقة:
هنا مثال أكثر تطوراً:
في تجربتي ، أصبحت هذه الطريقة أقل شعبية بسبب استخدام الأدوات الرقمية. إذا كنت تريد أن تبدو البطاقة كعلبة قديمة ممزقة ، فمن الأسهل تطبيق نسيج الورق عليها بدلاً من رسمها يدويًا.
الأداة الأقوى في إنشاء حدود الخريطة هي التكرار. في أبسط الحالات ، يكفي تكرار سطر واحد لإنشاء سطرين:
يمكنك إضافة اهتمام إلى الخريطة عن طريق تغيير نمط العنصر المتكرر ، في هذه الحالة من خلال الجمع بين خط سميك واحد مع سطر مفرد رقيق:
اعتمادًا على العنصر ، تكون أشكال النمط المختلفة ممكنة. في هذا المثال ، يتكرر الخط ، لكن يتغير اللون:
لإنشاء أنماط أكثر تعقيدًا ، يمكنك استخدام "التكرار القابل للتكرار". يتكون هذا الحد من خمسة خطوط مفردة تقريبًا ذات عرض ومسافات مختلفة:
يكرر هذا الحد الخطوط ، لكنه يفصلها بحيث تبدو كحدود رفيعة منفصلة. في هذا الجزء من المنشور ، لن أتحدث عن معالجة الزوايا ، لكن الزوايا المختلفة للخطين تساعد أيضًا في خلق هذا الاختلاف.
هل هذين الخطين ، أربعة ، أو ستة؟ أعتقد أن كل هذا يتوقف على كيفية رسمها!
عنصر آخر في الأسلوب هو ملء الفراغ بين العناصر باللون أو النقش أو الملمس. في هذا المثال ، أصبحت الحدود أكثر إثارة للاهتمام بسبب ملء لون التمييز بين السطرين:
فيما يلي مثال على كيفية ملء الحدود بنمط:
أيضا ، يمكن تصميم العناصر بحيث تبدو ثلاثية الأبعاد. فيما يلي خريطة مظللة بها الحدود بحيث تبدو ضخمة:
في هذه الخريطة ، يتم تظليل الحدود لتبدو ثلاثية الأبعاد ، ويتم دمجها مع موقع الحدود داخل حواف الخريطة:
عنصر الحد المشترك الآخر هو المقياس في شكل خطوط متعددة الألوان:
هذه المشارب تشكل شبكة (
شبكة رسم الخرائط ). على الخرائط الحقيقية ، يساعد المقياس في تحديد المسافات ، لكن في الخرائط الخيالية يعد عنصر ديكور بشكل أساسي.
عادة ما يتم رسم هذه الخطوط بالأبيض والأسود ، ولكن في بعض الأحيان يتم إضافة اللون الأحمر أو بعض الألوان الأخرى:
يمكن أيضًا دمج هذا العنصر مع العناصر الأخرى ، كما في هذا المثال مع الخطوط والمقياس:
هذا المثال غير عادي بعض الشيء. عادة ما يكون المقياس (إن وجد) هو العنصر الأعمق في الحدود.
في هذه الخريطة ، هناك مستويات مختلفة ذات دقة مختلفة (بالإضافة إلى ملاحظات رونية غريبة!):
(في رديت ،
أخبرني المستخدم
AbouBenAdhem أن علامات الرونية هي الرقمان 48 و 47
مكتوبان في المسمارية البابلية. بالإضافة إلى ذلك ، تحتوي "المقاييس بدقة مختلفة" على ستة أقسام مقسمة إلى عشرة أقسام أصغر ، والتي تتوافق مع نظام الأرقام السداسية العشرية البابلية. أشير إلى مصادر الخرائط ، لكن هناك الكثير من القطع الصغيرة في هذا المنشور ، لذلك لم أكن قلقًا. ومع ذلك ،
فقد تم تصميم
هذه الخريطة بواسطة
Thomas Ray للمؤلف S.E. Boleyn ، لذلك ، قد يحدث الإجراء في كتبه في حاشية بابل.)
بالإضافة إلى الخطوط والحجم ، العنصر الأكثر شيوعًا هو نمط هندسي متكرر. غالبًا ما يتكون من أجزاء مثل الدوائر ، المعين والمستطيلات:
يمكن تظليل العناصر الهندسية ، مثل الخطوط ، لجعلها تبدو ثلاثية الأبعاد:
يمكن إنشاء حدود معقدة من خلال الجمع بين هذه العناصر بطرق مختلفة. هذه هي الحدود التي تجمع الخطوط والأنماط الهندسية والمقياس:
الأمثلة الموضحة أعلاه كانت عبارة عن بطاقات رقمية ، ولكن بالطبع يمكن القيام بنفس الشيء باستخدام بطاقات مكتوبة بخط اليد. فيما يلي مثال لنمط هندسي بسيط تم إنشاؤه باليد:
يمكن أيضًا دمج هذه العناصر بمرونة بعدة طرق. هنا نموذج هندسي مدمج مع "حافة خشنة":
في الأمثلة الموضحة أعلاه ، فإن النمط الهندسي بسيط للغاية. ولكن يمكنك إنشاء أنماط معقدة للغاية من خلال الجمع بين العناصر الهندسية الأساسية بطريقة مختلفة:
عنصر آخر شائع في النموذج هو النسيج أو عقدة سلتيك:
فيما يلي حدود خوص أكثر تعقيدًا تحتوي على اللون والمقياس وعناصر أخرى:
في هذه الخريطة ، يتم دمج النسيج مع عنصر حافة خشنة:
بالإضافة إلى الأنماط الهندسية والنسيج ، يمكن أن يكون أي نمط متكرر جزءًا من حدود البطاقة. فيما يلي مثال باستخدام الأشكال التي تشبه رؤوس الأسهم:
وهنا مثال على نمط موجة متكررة:
وأخيرًا ، تتم في بعض الأحيان إضافة الأحرف الرونية أو عناصر أخرى من الأبجدية الخيالية إلى حواف بطاقات الخيال:
الأمثلة المذكورة أعلاه مأخوذة من خرائط خيالية حديثة ، ولكن هنا مثال على خريطة تاريخية (القرن الثامن عشر) مع خطوط ونمط مرسومة باليد:
بالطبع ، يمكنك العثور على أمثلة للخرائط مع العديد من العناصر الأخرى على الحدود. بعض من أجملها مرسومة باليد بالكامل ولديها زخارف مصممة بعناية بحيث يمكنها تجاوز البطاقة نفسها (
World of Alma ، Francesca Baerald):
كما أنه يستحق القليل من الحديث عن
التناظر . مثل التكرار ، يعتبر التماثل أداة قوية ، وعادة ما تكون حدود الخريطة متماثلة أو تحتوي على عناصر متماثلة.
العديد من حدود الخريطة متناظرة من الداخل إلى الخارج ، كما في هذا المثال:
هنا ، تتكون الحدود من عدة خطوط مع وبدون تعبئة ، ولكن من الخارج إلى الداخل ، تتكرر بشكل مثالي بالنسبة إلى مركز الحدود.
في هذا المثال الأكثر تعقيدًا ، الحدود متناظرة ، باستثناء خطوط المقياس بالأبيض والأسود بالتناوب:
نظرًا لأن تكرار المقياس لا معنى له ، فإنه غالبًا ما يُعتبر عنصرًا منفصلاً ، حتى لو كانت بقية الحدود متماثلة.
بالإضافة إلى التماثل الداخلي والخارجي ، غالبًا ما تكون الحدود متناظرة على طولها. قد يكون لبعض الحدود الموضحة تصميم بسيط يمتد بطول حافة الخريطة بالكامل ، ولكن في معظم الحالات يكون النموذج قصير جدًا ويتكرر ، ويملأ الحدود من زاوية إلى أخرى:
لاحظ أنه في هذا المثال ، يحتوي النموذج على عنصر غير متماثل (من اليسار إلى اليمين) ، ولكن النمط العام متماثل ويتكرر:
أحد الاستثناءات البارزة لهذه القاعدة هو الحدود المملوءة بالرونية أو الأحرف الأبجدية. غالبًا ما يتضح أنها فريدة من نوعها ، كما لو كانت بعض الرسائل الطويلة مكتوبة على طول الحدود:
بالطبع ، هناك العديد من الأمثلة الأخرى لعناصر حدود الخريطة التي لم أضعها في الاعتبار هنا ، لكن لدينا بالفعل نقطة مرجعية جيدة. في الأجزاء القليلة التالية ، سوف أقوم بتطوير العديد من الوظائف في
Dragons Abound لوصف وعرض وتعيين حدود الخريطة بشكل مشابه لهذه الأمثلة. في الجزء الثاني ، سنبدأ بتعيين اللغة لوصف حدود الخرائط.
الجزء 2
في هذا الجزء ، سوف أقوم بإنشاء الإصدار الأولي من لغة وصف حدود الخريطة (MBDL).
لماذا قضاء بعض الوقت في إنشاء لغة وصف حدود الخريطة؟ أولاً ، سيكون هذا هو هدف جيلي الإجرائي. فيما بعد سأكتب خوارزمية لإنشاء حدود خريطة جديدة ، وسيكون إخراج هذه الخوارزمية بمثابة وصف للحدود الجديدة على MBDL. ثانياً ، ستكون MBDL بمثابة تمثيل نصي لحدود الخريطة. على وجه الخصوص ، أحتاج إلى أن أكون قادرًا على حفظ حدودي وإعادة استخدامها. للقيام بذلك ، أحتاج إلى تدوين نص يمكن كتابته واستخدامه لإعادة إنشاء حدود الخريطة.
سأبدأ في إنشاء MBDL عن طريق تحديد أبسط العناصر: السطر. الخط له اللون والعرض. لذلك ، في MBDL سأقدم السطر في هذا النموذج:
L(width, color)
فيما يلي بعض الأمثلة (آسف على مهاراتي في Photoshop):
يتم تقديم تسلسل العناصر من الخارج إلى الداخل (*) ، لذلك نحن نفترض أن هذه هي الحدود في أعلى الخريطة:
انظر إلى المثال الثاني - يتم تمثيل السطر ذو الحدود بثلاثة عناصر سطر منفصلة.
(* كان الرسم من الخارج إلى الداخل اختيارًا تعسفيًا - بدا لي فقط أنه أكثر طبيعية من تقديمه من الخارج إلى الخارج. لسوء الحظ ، كما تبين بعد ذلك بفترة وجيزة ، كان هناك سبب وجيه للعمل في الاتجاه المعاكس. سرعان ما أخبرك بذلك ، ولكن سيتم ترك كل شيء في المنشور - قديم ، لأن الأمر سيستغرق الكثير من الوقت لإعادة جميع الرسوم التوضيحية)مريح ، يمكن تمثيل المساحات كخطوط بدون لون:
لكن سيكون من المرئي أن يكون لديك عنصر مساحة رأسية محدد:
VS (العرض)
العناصر البسيطة التالية هي الأشكال الهندسية: المشارب ، المعين والحذف. من المفترض أن الخطوط ممتدة على طول الحدود بالكامل ، بحيث لا يكون لها طول محدد بشكل صريح. لكن الأشكال الهندسية لا يمكن أن تملأ الخط بالكامل ، لذلك ، بالإضافة إلى العرض (*) ، يجب أن يكون لكل منها طول ولون مخطط تفصيلي وعرض مخطط تفصيلي ولون تعبئة:
B(width, length, outline, outline width, fill)
D(width, length, outline, outline width, fill)
E(width, length, outline, outline width, fill)
(* قبلت أنني سأدرس العرض في الاتجاه من الخارج إلى الداخل ، ويتم قياس الطول على طول الحدود.)
فيما يلي أمثلة على الأشكال الهندسية البسيطة:
لكي تملأ هذه العناصر كامل طول الحدود ، يجب تكرارها. للإشارة إلى مجموعة العناصر التي سيتم تكرارها لملء طول الحد ، استخدم الأقواس المربعة:
[ element element element ... ]
فيما يلي مثال على نمط متكرر من المستطيلات و المعين:
سأحتاج في بعض الأحيان إلى مساحة (أفقية) بين عناصر نمط متكرر. على الرغم من أنه يمكنك استخدام عنصر بدون ألوان لإنشاء مساحة ، إلا أنه سيكون أكثر ذكاءً وأكثر ملاءمة لوجود عنصر مساحة أفقي:
HS(length)
الوظيفة الأخيرة اللازمة لهذا التكرار الأول من MBDL هي القدرة على تكديس العناصر فوق بعضها البعض. فيما يلي مثال على الحدود:
أسهل طريقة لوصفه هي خط أصفر عريض أسفل النموذج العلوي. يمكنك تنفيذ ذلك بطرق مختلفة (على سبيل المثال ، مساحة رأسية سلبية) ، لكنني قررت استخدام الأقواس المتعرجة للإشارة إلى ترتيب العناصر إلى الداخل:
{element element element ...}
في الحقيقة ، يخبرك هذا الإدخال بتذكر المكان الذي كان عليه النمط من الخارج إلى الداخل عند إدخال الأقواس ، ثم العودة إلى هذه النقطة عند ترك الأقواس. يمكن أيضًا اعتبار الأقواس بمثابة وصف للعناصر التي تشغل مساحة رأسية. لذلك ، يمكن وصف الحدود الموضحة أعلاه على النحو التالي:
L(1, black)
{L(20, yellow)}
VS(3)
[B(5, 10, black, 3, none)
D(5, 10, black,3,red)]
VS(3)
L(1, black)
نرسم خطًا أسود ونصلح ما نحن فيه ، ونرسم خطًا أصفر ، ثم نعود إلى الموضع الثابت سابقًا ، وننزل قليلاً ، ونرسم نمطًا من المستطيلات والقوافي ، وننزل قليلاً ، ثم نرسم خطًا أسودًا آخر.
هناك الكثير مما يجب عمله في MBDL ، لكن هذا يكفي لوصف الحدود العديدة للخرائط. الخطوة التالية هي تحويل وصف الحدود على MBDL إلى الحد نفسه. يشبه هذا تحويل تمثيل مكتوب لبرنامج كمبيوتر (مثل Javascript) إلى تنفيذ هذا البرنامج. تتمثل المرحلة الأولى في
التحليل اللغوي (تحليل) للغة - تحويل النص المصدر إلى حدود حقيقية للخريطة أو إلى نوع ما من الأشكال الوسيطة ، والذي يسهل تحويله إلى حد.
التحليل هو مجال مدروس جيدًا لعلوم الكمبيوتر. تحليل اللغة ليس بسيطًا جدًا ، ولكن في حالتنا ، من الجيد (*) أن تكون MBDL قواعد نحوية
خالية من السياق . يتم تحليل قواعد اللغة الخالية من السياق بسهولة إلى حد ما ، وهناك العديد من
أدوات تحليل جافا سكريبت لهم. لقد استقرت على
Nearley.js ، والتي تبدو ناضجة تمامًا (والأهم من ذلك) أداة موثقة جيدًا.
(* هذا ليس مجرد حظ ، لقد تأكدت من أن اللغة كانت خالية من السياق.)لن أقدم لك قواعد نحوية خالية من السياق ، لكن بناء جملة Nearley بسيط للغاية ويجب أن تفهم المعنى دون أي مشاكل. يتكون القواعد النحوية الأدنى من مجموعة من القواعد. كل قاعدة لها حرف إلى اليسار ، سهم ، والجزء الأيمن من القاعدة ، والتي يمكن أن تكون سلسلة من الأحرف وغير الأحرف ، بالإضافة إلى خيارات متعددة مفصولة بـ "|" (أو):
border -> element | element border
element -> “ L"
تنص كل قاعدة من القواعد على أنه يمكن استبدال الجانب الأيسر بأي من الخيارات الموجودة على الجانب الأيمن. بمعنى أن القاعدة الأولى تقول أن الحدود عنصر أو عنصر متبوعًا بحد آخر. التي يمكن أن تكون في حد ذاتها عنصرا ، أو عنصرا يليه حد ، وهلم جرا. تقول القاعدة الثانية أن العنصر لا يمكن أن يكون إلا سلسلة "L". أي أن هذه القواعد تتوافق مع هذه الحدود معًا:
L
LLL
ولا تتوافق مع هذه الحدود:
X
L3L
بالمناسبة ، إذا كنت ترغب في تجربة هذا (أو أي قواعد) أخرى في Nearley ، فهناك رمل على الإنترنت لهذا
هنا . يمكنك إدخال قواعد النحو والاختبار لمعرفة ما يطابقه ولا يتطابق.
فيما يلي تعريف أكثر اكتمالا لخط بدائي:
@builtin “number.ne"
@builtin “string.ne"
border -> element | element border
element -> “L(" decimal “," dqstring “)"
يحتوي Nearley على العديد من العناصر المضمنة الشائعة ، والرقم واحد منهم. لذلك ، يمكنني استخدامه للتعرف على العرض العددي لخط بدائي. للتعرف على اللون ، أستخدم عنصرًا مضمنًا آخر وأسمح باستخدام أي سلسلة في علامات تنصيص مزدوجة.
سيكون من الجيد إضافة مسافات بين شخصيات مختلفة ، لذلك دعونا نفعل ذلك. يدعم Nearley فئات الأحرف و RBNF لشيء "صفر أو أكثر" مع ": *" ، لذلك يمكنني استخدام هذا لتحديد "صفر أو أكثر من المسافات" ولصقها في أي مكان للسماح بمسافات في الأوصاف:
@builtin "number.ne"
@builtin "string.ne"
border -> element | element border
WS -> [\s]:*
number -> WS decimal WS
color -> WS dqstring WS
element -> "L(" number "," color ")"
ومع ذلك ، فإن استخدام WS في كل مكان يجعل من الصعب قراءة القواعد النحوية ، لذلك سأتخلى عنها ، ولكن تخيل أنها كذلك.
يمكن أن يكون العنصر أيضًا مسافة عمودية:
@builtin "number.ne"
@builtin "string.ne"
border -> element | element " " border
number -> decimal
color -> dqstring
element -> "L(" number "," color ")"
element -> "VS(" number ")"
هذا يتوافق مع هذه الحدود
L(3.5,"black") VS(3.5)
بعد ذلك تأتي أوليات الشريط ، المعين والقطع الناقص.
@builtin "number.ne"
@builtin "string.ne"
border -> element | element " " border
number -> decimal
color -> dqstring
element -> "L(" number "," color ")"
element -> "VS(" number ")"
geometric -> "B(" number "," number "," color "," number "," color ")"
geometric -> "E(" number "," number "," color "," number "," color ")"
geometric -> "D(" number "," number "," color "," number "," color ")"
وسوف تتطابق مع هذه العناصر
B(34, 17, "white", 3, "black")
(لاحظ أن العناصر الهندسية الأولية ليست "عناصر" لأنها لا يمكن أن تكون بمفردها في المستوى الأعلى. يجب أن تكون محاطة بنمط.)
أحتاج أيضًا إلى مساحة أفقية بدائية:
@builtin "number.ne"
@builtin "string.ne"
border -> element | element " " border
number -> decimal
color -> dqstring
element -> "L(" number "," color ")"
element -> "VS(" number ")"
geometric -> "B(" number "," number "," color "," number "," color ")"
geometric -> "E(" number "," number "," color "," number "," color ")"
geometric -> "D(" number "," number "," color "," number "," color ")"
geometric -> "HS(" number ")"
الآن سأضيف عملية نمط (تكرار). هذا هو تسلسل عنصر واحد أو أكثر داخل الأقواس المربعة. سأستخدم مشغل RBNF ": +" ، والذي يعني هنا "واحد أو أكثر".
@builtin "number.ne"
@builtin "string.ne"
border -> element | element " " border
number -> decimal
color -> dqstring
element -> "L(" number "," color ")"
element -> "VS(" number ")"
geometric -> "B(" number "," number "," color "," number "," color ")"
geometric -> "E(" number "," number "," color "," number "," color ")"
geometric -> "D(" number "," number "," color "," number "," color ")"
geometric -> "HS(" number ")"
element -> "[" (geometric):+ "]"
لاحظ أنه لا يمكن ملء النموذج إلا بالأولويات الهندسية. لا يمكننا ، على سبيل المثال ، وضع خط داخل النموذج. سيتطابق عنصر النمط الآن مع شيء من هذا القبيل.
[B(34,17,"white",3,"black")E(13,21,"white",3,"rgb(27,0,0)")]
الجزء الأخير من اللغة هو عامل التراكب. هذا هو أي عدد من العناصر داخل الأقواس.
@builtin "number.ne"
@builtin "string.ne"
border -> element | element " " border
number -> decimal
color -> dqstring
element -> "L(" number "," color ")"
element -> "VS(" number ")"
geometric -> "B(" number "," number "," color "," number "," color ")"
geometric -> "E(" number "," number "," color "," number "," color ")"
geometric -> "D(" number "," number "," color "," number "," color ")"
geometric -> "HS(" number ")"
element -> "[" (geometric ):+ "]"
element -> "{" (element ):+ "}"
مما يسمح لنا بالقيام بما يلي:
{L(3.5,"rgb(98,76,15)")VS(3.5)}
(لاحظ أنه على عكس عامل التكرار ، يمكن استخدام عامل التراكب داخليًا.)
بعد تنظيف الوصف وإضافة مسافات إلى الأماكن اللازمة ، نحصل على قواعد MBDL التالية:
@builtin "number.ne"
@builtin "string.ne"
border -> (element WS):+
WS -> [\s]:*
number -> WS decimal WS
color -> WS dqstring WS
element -> "L(" number "," color ")"
element -> "VS(" number ")"
element -> "(" WS (element WS):+ ")"
element -> "[" WS (geometric WS):+ "]"
geometric -> "B(" number "," number "," color "," number "," color ")"
geometric -> "E(" number "," number "," color "," number "," color ")"
geometric -> "D(" number "," number "," color "," number "," color ")"
geometric -> "HS(" number ")"
لذلك ، تم تعريف MBDL الآن وقمنا بإنشاء قواعد اللغة. يمكن استخدامه مع Nearley للتعرف على سلاسل اللغة. قبل الخوض في MBDL / Nearley ، أود تنفيذ الأولويات المستخدمة في MBDL بحيث يمكن عرض الحدود الموضحة في MBDL. هذا سنفعله في الجزء التالي.
الجزء 3
الآن سوف نبدأ في تنفيذ البدائية التقديم أنفسهم. (في هذه المرحلة ، لست مضطرًا إلى ربط المحلل اللغوي بالأولويات التجسيدية بعد. للاختبار ، سأتصل بهم يدويًا فقط.)
لنبدأ بالخط البدائي. أذكر ما يبدو عليه:
L(width, color)
بالإضافة إلى العرض واللون ، هناك معلمة ضمنية هنا - المسافة من الحافة الخارجية للخريطة. (أرسم الحدود من حافة الخريطة إلى الخارج. لاحظ أننا بدأنا من أخرى مختلفة!) لا ينبغي أن يشير إلى MBDL ، لأنه يمكن تتبع ذلك بواسطة المترجم الذي يقوم بتشغيل MBDL لرسم الحدود. ومع ذلك ، يجب أن يكون هذا مدخلاً لكل العناصر الأولية التي تجعلهم يعرفون أين يرسمونها. سأدعو هذه المعلمة الإزاحة.
إذا كنت بحاجة فقط لرسم حدود على طول الجزء العلوي من الخريطة ، فسيكون من السهل تنفيذ الخط البدائي. ومع ذلك ، في الواقع ، سوف أحتاج إلى السحب من أعلاه. أسفل ، اليسار واليمين. (ربما سأدرك في يوم من الأيام حدودًا منحنية أو منحنية ، لكن الآن سنلتزم بالحدود المستطيلة القياسية.) بالإضافة إلى ذلك ، يعتمد طول عنصر الخط وموقعه على حجم الخريطة (وكذلك على الإزاحة). لذلك ، كمعلمات ، أحتاج إلى كل هذه البيانات.
بعد تعيين كل هذه المعلمات ، يكفي إنشاء سطر بدائي واستخدامه لرسم خط حول الخريطة:
(لاحظ أنني أستخدم وظائف متنوعة لـ
Dragons Abound لرسم الخط "المكتوب بخط اليد"). دعونا نحاول إنشاء حد أكثر تعقيدًا:
L(3, black) L(10, gold) L(3, black)
يبدو مثل هذا:
جيد جدا لاحظ أن هناك أماكن لا تتماشى فيها الخطوط السوداء والخط الذهبي تمامًا بسبب التقلبات. إذا كنت ترغب في التخلص من هذه المواقع ، يمكنك ببساطة تقليل مقدار التذبذب.
تنفيذ بدائية الفضاء الرأسي هو بسيط جدا. ينفذ فقط زيادة تعويض. دعنا نضيف مساحة صغيرة:
L(3, black) L(10, gold) L(3, black)
VS(5)
L(3, black) L(10, red) L(3, black)
عند رسم خطوط ، يمكن تحقيق الزوايا من خلال الرسم بين الإزاحة والرسم على طول الخريطة في اتجاه عقارب الساعة. لكن بشكل عام ، أحتاج إلى تطبيق الاقتطاع على كل جانب من حدود الخريطة لإنشاء
اتصال زاوي بحواف مائلة . سيكون هذا ضروريًا لإنشاء حدود مع أنماط مرتبطة بشكل صحيح في الزوايا ، وفي الحالة العامة ستلغي الحاجة إلى رسم العناصر ذات الحواف بزاوية قد تكون مطلوبة. (*)
(ملحوظة: كما قيل في الأجزاء التالية ، رفضت بمرور الوقت استخدام مناطق الاقتطاع عند تنفيذ الزوايا. والسبب الرئيسي هو إنشاء زوايا معقدة ، على سبيل المثال ، الإزاحة المربعة:مناطق اقتطاع متزايدة التعقيد مطلوبة. أيضًا ، بمرور الوقت ، وجدت طريقة أفضل للتعامل مع الأنماط في الزوايا. بدلاً من العودة وإعادة كتابة هذا الجزء من المقالة ، قررت تركه لتوضيح عملية "الإبداع".)الفكرة الرئيسية هي اقتطاع كل الحدود قطريًا وإنشاء أربعة مناطق مقطوعة يتم فيها رسم كل جانب من الحدود:
عند الاقتطاع ، سيتم قطع كل شيء يتم رسمه في المنطقة المقابلة بالزاوية المطلوبة.
لسوء الحظ ، يؤدي هذا إلى إنشاء فجوات صغيرة على طول الخطوط القطرية ، ربما لأن المستعرض ينفذ تجانسًا على طول الحافة المقطوعة. أظهر الاختبار أن الخلفية تتألق عبر الفجوة بين الحوافين. كان من الممكن إصلاح ذلك عن طريق توسيع أحد الأقنعة قليلاً (يبدو أن نصف البكسل يكفي) ، لكن هذا في بعض الأحيان لا يحل المشكلة.
القادمة تحتاج إلى تنفيذ الأشكال الهندسية. على عكس الخطوط ، يتم تكرارها في النموذج ، وملء جانب الحد من الخريطة:
يمكن للشخص رسم هذا النمط من اليسار إلى اليمين ، ورسم مستطيل ، المعين ، ثم تكرار نفس الشيء حتى يتم ملء الحد بالكامل. لذلك ، يمكن أيضًا تنفيذ ذلك في البرنامج من خلال رسم نمط على طول الحدود. ومع ذلك ، سيكون من الأسهل أولاً رسم جميع المستطيلات ، ثم جميع المعينات. سيكون كافياً فقط أن ترسم على طول الحدود نفس الشكل الهندسي على فترات. ومن المريح جدًا أن يكون لكل عنصر نفس الفاصل الزمني. بالطبع ، لن يقوم الشخص بذلك ، لأنه من الصعب جدًا ترتيب العناصر في الأماكن المناسبة ، لكن هذه ليست مشكلة للبرنامج.
أي أن الإجراء الخاص برسم الأشكال الهندسية البسيطة يحتاج إلى معلمات يتم فيها نقل جميع أبعاد وألوان الشكل (أي العرض والطول وسمك الخط ولون الخط والملء) ، بالإضافة إلى موضع البدء (والذي سيتضح قريبًا ، سأنظر في مركز الشكل) ، والفاصل الزمني للمسافة الأفقية للانتقال بين التكرار ، وعدد التكرارات. سيكون من المناسب أيضًا الإشارة إلى اتجاه التكرار في شكل المتجه [dx، dy] ، حتى نتمكن من إجراء التكرار من اليسار إلى اليمين ، من اليمين إلى اليسار ، لأعلى أو لأسفل ، ببساطة تغيير المتجه ونقطة البداية. ضعها معًا واحصل على شريط من الأشكال المتكررة:
باستخدام هذا الرمز عدة مرات وتقديمه بنفس الإزاحة ، يمكنني دمج الخطين الأبيض والأسود لإنشاء مقياس الخريطة:
قبل أن أبدأ في التعرف على كيفية تطبيق كل هذا على الحدود الحقيقية للخريطة ، دعونا أولاً ننفذ نفس الوظيفة للقطع الناقص ونسق المعين.
المعينات هي مجرد مستطيلات ذات رؤوس مستديرة ، لذلك تحتاج فقط إلى إجراء تغيير بسيط في الكود. اتضح أنني لا أزال لا أملك رمزًا جاهزًا لتقديم القطع الناقص ، لكن من السهل جدًا أخذ
وجهة النظر البيضاوية للقطع الناقص وإنشاء وظيفة تعطيني نقاط القطع الناقص:
فيما يلي مثال (تم إنشاؤه يدويًا) يستخدم الميزات التي تم تنفيذها أعلاه:
لمثل هذه الكمية الصغيرة من الكود ، تبدو جيدة!
لنقم الآن بحل حالة الحدود المعقدة بعناصر متكررة: الزوايا.
إذا كانت هناك حدود مع العناصر المكررة ، فهناك عدة طرق لحل المشكلة مع الزوايا. الأول هو ضبط التكرار بحيث يتم تنفيذها في الزوايا دون زواج ملحوظ:
خيار آخر هو إيقاف التكرار في مكان ما بالقرب من الزاوية على كلا الجانبين. يتم ذلك غالبًا إذا كان لا يمكن "تدوير" النموذج بسهولة في الزاوية:
الخيار الأخير هو إغلاق النموذج مع بعض الزخارف الزاوية:
في يوم من الأيام ، سأصل إلى الأركان ، لكن الآن سنستخدم الخيار الأول. كيف تجعل "نمطًا" من المشارب أو الدوائر "تدور" في زوايا الخريطة دون ثغرات؟
الفكرة الرئيسية هي وضع عنصر النمط في الزاوية تمامًا بحيث يكون نصفه على حافة إحدى الخريطة والآخر على الحافة المجاورة. في هذا المثال ، الدائرة في الزاوية تمامًا ويمكن رسمها من أي اتجاه:
في حالات أخرى ، يكون العنصر نصف مرسوم في اتجاه واحد ، والنصف الآخر ، لكن الحواف تتزامن:
في هذه الحالة ، يتم رسم شريط أبيض على كلا الجانبين ، ولكنه متصل في الزاوية دون وجود فجوات.
هناك جانبان يجب مراعاتهما عند وضع عنصر في الزاوية.
أولاً ، سيتم تقسيم عنصر الركن وعكسه بالنسبة إلى المائل الذي يمر عبر مركز العنصر. العناصر ذات التماثل الشعاعي ، على سبيل المثال المربعات والدوائر والنجوم ، لن تغير شكلها. العناصر بدون تناسق شعاعي ، على سبيل المثال ، المستطيلات و المعين ، سوف تتغير الشكل عند النسخ المتطابق بالنسبة للقطري.
ثانياً ، لكي تتصل العناصر الأساسية للجانبين بشكل صحيح ، يجب أن يكون هناك عدد صحيح من العناصر (*) على جانبي الخريطة. ليس من الضروري أن يكون العدد نفسه ، ولكن يجب أن يكون هناك عدد صحيح من العناصر على كلا الجانبين. إذا تم احتواء عدد كسور من النقوش على جانب واحد ، فلن يتزامن النموذج من جانب واحد مع الجانب المجاور.
(* في بعض الحالات ، على سبيل المثال ، مع خطوط طويلة ، قد يحدث التكرار الجزئي مع التكرار الكامل وسيتم محاذاة العناصر على أي حال. ومع ذلك ، فإن عنصر الركن الناتج سيكون غير متماثل ويختلف في الطول عن نفس العنصر على جانبي الخريطة. ويمكن ملاحظة مثال على ذلك:يحدث شريط أبيض الحجم بتكرار جزئي مختلف ونتيجة لذلك يتم الحصول على عنصر تحول بالنسبة للمركز. بالنسبة إلى مقياس الخريطة ، ليس هذا هو الحال دائمًا ، لأنه يُظهر المسافة المطلقة ولا يجب أن يكون متماثلًا. لكن بالنسبة للنمط الزخرفي ، عادة ما يبدو هذا سيئًا.)في ما يلي مثال يوضح كيفية تقليص عدد صحيح من التكرارات في الزاوية تمامًا:
إذا كنت تفعل الشيء نفسه من جميع الجوانب الأربعة ، فسوف تتزامن الزوايا وسيتم تحديد النمط بسلاسة على طول الحدود بالكامل:
عند الفحص الدقيق ، ستلاحظ أن النمط لا يحدث بالضبط في الزوايا. نصف الدائرة في كل زاوية مأخوذة من كل جانب ، وهذان النصفان ، بشكل مستقل عن بعضهما البعض ، "مرسومة باليد" ، لذا فهي ليست مثالية. لكن الآن هم قريبون بما فيه الكفاية لهذا.
لذلك ، يمكننا تحقيق اتصال مثالي للنمط في الزوايا ، واختيار عدد صحيح من التكرارات لكل حافة. ومع ذلك ، فإن الحل لهذه المشكلة هو غير بديهي.
أولاً ، افترض أننا نعرف أن طول الجانب يبلغ 866 بكسل ، ونريد تكرار العنصر 43 مرة. ثم يجب تكرار العنصر كل 20.14 بكسل. كيف يمكننا ضبط الطول المحدد للعنصر (وفي الحالة العامة ، نمط من العناصر)؟ في المثال أعلاه ، أضفت مساحة إضافية بين الدوائر. ولكن إذا لمست الدوائر بعضها البعض في البداية ، فسيؤدي ذلك إلى تغيير النمط. ربما يستحق الأمر تمديد الدوائر بحيث تستمر في لمس بعضها البعض؟
الآن العناصر تلمس ، لكن الدوائر تحولت إلى علامات استهلالية ، والزوايا لها شكل غريب. (تذكر ، قلت إن العناصر التي لا تحتوي على تناسق شعاعي تغير شكلها عندما تنعكس نسبة إلى زاوية؟ لن تكون هذه مشكلة كبيرة.) أو ربما يستحق الأمر ضغط كل العناصر بحيث تلامس بعضها البعض وتتناسب مع الطول المناسب:
ولكن من أجل تحقيق ذلك ، نحتاج إلى جعل العناصر أصغر بكثير مما كانت عليه في الأصل. لا يبدو أي من هذه الخيارات مثاليًا.
المشكلة الثانية تحدث عندما تكون جوانب البطاقة بأحجام مختلفة. نحن الآن بحاجة إلى حل مشكلة إيجاد عدد صحيح من التكرارات المناسبة لكلا الجانبين. سيكون من المثالي إيجاد حل واحد يناسب كلا الجانبين. لكنني لا أريد القيام بذلك على حساب الكثير من تغيير النمط. قد يكون من الأفضل إنشاء أنماط مختلفة قليلاً على كلا الجانبين إذا كان كلاهما قريبًا بما يكفي من النموذج الأصلي.
, , , :
, . , , .
, ? . , !
4
, . , . , ( ), . — , — . , !
, , . «» , . , . , , , , .
, , . , . (: .) , . , — , !
:
. . , , , , 45 . :
, .
( , !)2:1:
, , . , , , .
, :
. :
, . , ; , , . .
:
:
, , .
, , . : , ; , !
, , . :
, , — . - , , .
, , , ( , ), . :
, ( ):
, , , proof of concept .
5
2 Map Border Description Language (MBDL), 3 4 . , MBDL .
3 MBDL , Javascript-
Nearley . :
@builtin " number.ne"
@builtin " string.ne"
border -> (element WS):+
WS -> [\s]:*
number -> WS decimal WS
color -> WS dqstring WS
element -> " L(" number " ," color " )"
element -> " VS(" number " )"
element -> " (" WS (element WS):+ " )"
element -> " [" WS (geometric WS):+ " ]"
geometric -> " B(" number " ," number " ," color " ," number " ," color " )"
geometric -> " E(" number " ," number " ," color " ," number " ," color " )"
geometric -> " D(" number " ," number " ," color " ," number " ," color " )"
geometric -> " HS(" number " )"
, Nearley , , . ,
test -> " A" | " B" | " C"
A
Nearley
[ " A" ]
— «A», .
Nearley, ?
number -> WS decimal WS
, . , WS, , decimal, , WS. " 57", :
[
[ " " ],
[ "5", "7" ],
[ ]
]
Nearley ,
. — , — .
Dragons Abound , , .
, Nearley , . , ()
decimal , Javascript, ,
number :
[
[ " " ],
57,
[ ]
]
Nearley , , , . — Javascript . ,
number . , , . , :
number -> WS decimal WS {% default => default[1] %}
( ) , Javascript
decimal . ,
number .
, . , Nearley MBDL Javascript, , «op». :
element -> " L(" number " ," color " )" {% data=> {op: " L", width: data[1], color: data[3]} %}
«L(13,black)» Javascript:
{op: " L", width: 13, color: " black"}
() .
L( 415, “black")
VS(5)
[B(1, 2, “black", 3, “white") HS(5) E(1, 2, “black", 3, “white")]
[
{op: "L", width: 415, color: "black"},
{op: "VS", width: 5},
{op: "P",
elements: [{op: "B", width: 1, length: 2,
olColor: "black", olWidth: 3,
fill: "white"},
{op: "HS", width: 5},
{op: "E", width: 1, length: 2,
olColor: "black", olWidth: 3,
fill: "white"}]}
]
.
— Nearley Javascript, ? . .
-, MBDL (*) , . , ( ) , . , , , . .
(* , .)-, Javascript Nearley , Javascript , . , , .. , Nearley, , , .
, .
, MBDL . . (, ) .
.
-, . , , , , . , , , . , . ; (VS).
— . , . , , .
, :
, (?) , :
[
{op:'P', elements: [
{op:'B', width: 10, length: 37, lineWidth: 2, color: 'black', fill: 'white'},
{op:'B', width: 10, length: 37, lineWidth: 2, color: 'black', fill: 'black'},
]},
{op:'VS', width: 2},
{op:'L', width:3, color: 'black'},
{op:'PUSH'},
{op:'L', width:10, color: 'rgb(222,183,64)'},
{op:'POP'},
{op:'PUSH'},
{op:'P', elements: [
{op:'E', width: 5, length: 5, lineWidth: 1, color: 'black', fill: 'red'},
{op:'HS', length: 10},
]},
{op:'L', width:3, color: 'black'},
{op:'POP'},
{op:'VS', width: 2},
{op:'P', elements: [
{op:'E', width: 2, length: 2, lineWidth: 0, color: 'black', fill: 'white'},
{op:'HS', length: 13},
]},
]
. , !
MBDL. : , . MBDL:
[B(5,37,"black",2,"white") B(5,37,"black",2,"black")]
VS(3)
L(3,"black")
{L(10,"rgb(222,183,64)")}
[E(5,5,"black",1,"red") HS(-5) E(2,2,"none",0,"white") HS(10)]
L(3,"black")
, . , , .
, , , , :
, : , . — !
6
, MBDL, , , , MBDL.
. , : , :
, - , - , 90 , . , .
, , , , . MBDL . , , :
element -> "O(MITER)"
element -> "O(STOPPED)"
element -> "O(STOPPED," number ")"
( .) «MITER» «STOPPED» . STOPPED , - . , .
STOPPED, . إليك ما يبدو عليه:
- MITER, . ( ) STOPPED. , .
. -, , , — . , . . , , . -, , ( ) . / , . , , .
, . , ( ). , , .
.
STOPPED STOPPED :
, . لماذا؟ , , , . , .
.
— , :
!
Option:
element -> "O(SQOFFSET)"
element -> "O(SQOFFSET," number ")"
; . . . , , , :
, , , . SQOFFSET ; SQOFFSET. , , .
, , . , . , . .
, «» . - , , , . :
, .
. :
, , :
, . , , , . , ; . , . :
— . , , .
, :
. :
: «, , ».
: « !»
.
, , , , :
, . . (, . , , .)
, :
, , « ». ( , .)
, , , ? :
, .