ฉันจะใช้บทสนทนาการแยกสาขาในจาวาสคริปต์ได้อย่างไร


11

ฉันสร้างเกมประเภทvisual visualพื้นฐานขึ้นใน JavaScript ฉันเป็นผู้เริ่มต้นดังนั้นฉันแค่ทำเพื่อความสนุกและการเรียนรู้และเนื่องจากการวางแผนที่ไม่ถูกต้องฉันได้พบกับปัญหาเล็กน้อยเมื่อคุณไปที่สาขาในการสนทนา

ขณะนี้ฉันถือสคริปต์สำหรับเกมในตัวแปรสตริงและฉันแบ่งแต่ละฉากด้วยแท็กเช่น "# ~" เป็นอาร์เรย์ที่เล็กลงเพื่อให้สคริปต์เกมมีลักษณะดังนี้:

var script = "Hello World!#~How are you today?"
var gameText = script.split("#~");
//gameText[0]= Hello World!

สิ่งนี้ใช้งานได้ดีสำหรับสิ่งที่เป็นเส้นตรง แต่ฉันจะจัดการสาขาในต้นไม้บทสนทนาได้อย่างไร วิธีนี้ดูซับซ้อนมากเพราะฉันต้องรู้ว่าแต่ละเส้นทางนั้นนานแค่ไหนแล้วถ้าฉันต้องการเปลี่ยนแปลงอะไรมันจะปวดหัว

ฉันจะทำสิ่งนี้ในวิธีที่ง่ายกว่าได้อย่างไร ฉันพยายามติดกับวานิลลาจาวาสคริปต์เพราะฉันต้องการให้เกมทำงานร่วมกับ Web Run Time


วิดีโอนี้สามารถให้ความคิดกับคุณ: youtube.com/watch?v=XM2t5H7kY6Y
JCM

ฉันเพิ่งต้องพัฒนาบางสิ่งสำหรับสิ่งนี้โดยใช้ Node และเลือกใช้โครงสร้างไฟล์ข้อความพื้นฐานมาก คุณสามารถดูโค้ดผลลัพธ์และรูปแบบข้อความได้ที่: github.com/scottbw/dialoguejsรหัสคือ GPL อย่าลังเลที่จะใช้ ฉันแน่ใจว่ามันจะไม่ยากที่จะปรับตัวสำหรับเกมที่ไม่ใช่โหนด JS - แทนที่ส่วน "fs.load ()" ด้วย Ajax
Scott Wilson

ตรวจสอบหมึกเป็นภาษาสคริปต์เรื่องราวแตกแขนงพัฒนาโดยInkle สตูดิโอ มีการรวมหมึกเชิงโปรแกรม (Java, Javascript, C #) และทรัพยากรบุคคลที่สามมากมาย หมึกถูกใช้ในเกมเชิงพาณิชย์มากมายเช่นกัน ในที่สุดก็มีโปรแกรมแก้ไขเดสก์ท็อปInkyที่สามารถตรวจสอบไวยากรณ์และ 'เล่น' กล่องโต้ตอบการแยกสาขาของคุณ
Big Rich

คำตอบ:


8

คำตอบของฟิลิปป์แสดงให้เห็นทิศทางที่ถูกต้องแล้ว ฉันแค่คิดว่าโครงสร้างข้อมูลนั้นไม่มีความจำเป็น ข้อความสั้นจะง่ายต่อการเขียนและอ่าน

แม้ว่าข้อความสั้น ๆ จะทำให้อัลกอริทึมมีความซับซ้อนมากขึ้น แต่นั่นก็คุ้มค่าที่จะทำเพราะคุณเขียนอัลกอริธึมเพียงครั้งเดียว แต่เวลาส่วนใหญ่ของคุณจะใช้ในการเขียนและบำรุงรักษาเรื่องราว ดังนั้นปรับให้เหมาะสมสำหรับการทำส่วนที่ง่ายขึ้นคุณจะใช้เวลาทำ

var story = [
  { m: "Hi!" },
  { m: "This is my new game." },
  { question: "Do you like it?", answers: [
    { m: "yes", next: "like_yes" },
    { m: "no", next: "like_no" },
  ] },
  { label: "like_yes", m: "I am happy you like my game!", next: "like_end" },
  { label: "like_no", m: "You made me sad!", next: "like_end" },
  { label: "like_end" },
  { m: "OK, let's change the topic" }
];

คำอธิบายบางประการสำหรับการออกแบบนี้:

เรื่องราวทั้งหมดเขียนขึ้นในอาเรย์เดียว คุณไม่จำเป็นต้องระบุหมายเลขพวกเขาจะได้รับโดยอัตโนมัติโดยไวยากรณ์อาร์เรย์: รายการแรกมีดัชนี 0 หนึ่งรายการถัดไปมีดัชนี 1 ฯลฯ

ในกรณีส่วนใหญ่ไม่จำเป็นต้องเขียนหมายเลขของขั้นตอนต่อไปนี้ ฉันคิดว่าข้อความส่วนใหญ่ไม่ใช่กิ่งไม้ ลองทำ "ขั้นตอนต่อไปคือรายการต่อไปนี้" เป็นค่าเริ่มต้นและทำบันทึกเมื่อเป็นอย่างอื่นเท่านั้น

สำหรับการกระโดดใช้ป้ายกำกับไม่ใช่ตัวเลข จากนั้นหากคุณเพิ่มหรือลบสองสามบรรทัดในภายหลังตรรกะของเรื่องราวจะถูกเก็บรักษาไว้และคุณไม่จำเป็นต้องปรับตัวเลข

ค้นหาการประนีประนอมที่เหมาะสมระหว่างความชัดเจนและความสั้น ตัวอย่างเช่นฉันแนะนำให้เขียน "m" แทน "message" เพราะนั่นจะเป็นคำสั่งที่ใช้บ่อยที่สุดดังนั้นการทำให้สั้นจะทำให้ข้อความอ่านง่ายขึ้น แต่ไม่จำเป็นต้องย่อคำหลักที่เหลือให้สั้นลง (อย่างไรก็ตามทำตามที่คุณต้องการสิ่งสำคัญคือทำให้มันชัดเจนที่สุดสำหรับคุณอีกวิธีหนึ่งคุณสามารถสนับสนุนทั้ง "m" และ "ข้อความ" เป็นคำหลักที่ถูกต้อง)

อัลกอริทึมสำหรับเกมควรเป็นดังนี้:

function execute_game() {
  var current_line = 0;
  while (current_line < story.length) {
    var current_step = story[current_line];
    if (undefined !== current_step.m) {

      display_message(current_step.m);
      if (undefined !== current_step.next) {
        current_line = find_label(current_step.next);
      } else {
        current_line = current_line + 1;
      }

    } else if (undefined !== current_step.question) {

      // display the question: current_step.question
      // display the answers: current_step.answers
      // choose an answer
      // and change current_line accordingly

    }
  }
}

อย่างไรก็ตามแนวคิดเหล่านี้ได้รับแรงบันดาลใจจากRen'Pyซึ่งไม่ใช่สิ่งที่คุณต้องการอย่างแน่นอน (ไม่ใช่ JavaScript ไม่ใช่เว็บ) แต่สามารถให้ความคิดดีๆแก่คุณได้


ขอบคุณสำหรับคำอธิบายในเชิงลึกฉันไม่ทราบว่าอาร์เรย์สามารถทำงานในแบบที่คุณและฟิลิปป์แสดงได้ฉันคิดว่าพวกเขาทำได้เพียงแค่มีสตริงหรือตัวเลข
นักทำแผนที่ Silent

1
ฉันพยายามใช้โซลูชันของคุณแล้วและใช้งานได้ดีแม้ว่าฉันคิดว่าในบางแห่ง({ label: "like_yes"; m: "I am happy you like my game!"; next: "like_end" },)ควรมี ',' ไม่ใช่ '; นอกจากนี้ในวงเล็บปีกกาสิ่งที่เรียกว่าอะไร? นั่นคือวัตถุภายในอาร์เรย์หรือไม่? ถ้าฉันต้องการข้อมูลเพิ่มเติมเกี่ยวกับวิธีใช้สิ่งที่ฉันจะค้นหา
นักทำแผนที่ Silent

ใช่{...}เป็นวัตถุ ใน JavaScript วัตถุคืออาเรย์แบบเชื่อมโยงคีย์ - ค่า (พร้อมฟังก์ชันพิเศษบางอย่างที่ไม่ได้ใช้ในตัวอย่างนี้) คล้ายกับอาเรย์ใน PHP หรือแผนที่ใน Java สำหรับข้อมูลเพิ่มเติมโปรดดูบทความ Wikipedia เกี่ยวกับ JavaScript และ ECMAScript และเอกสารที่เชื่อมโยงจากที่นั่นโดยเฉพาะเอกสาร ECMAScript ที่เป็นทางการ
Viliam Búr

1
btw โปรดทราบว่าโครงสร้างข้อมูลที่เขาแนะนำที่นี่เป็นพื้น JSON โดยส่วนตัวฉันขอแนะนำให้ไปที่ JSON (ส่วนใหญ่จะเพิ่มวงเล็บปีกกาและ "ต้นไม้": รอบ ๆ สิ่งทั้งหมดเช่น {"tree": [etc]}) จากนั้นคุณสามารถจัดเก็บแผนผังการสนทนาของคุณในไฟล์ภายนอก การนำข้อมูลของคุณไปไว้ในไฟล์ภายนอกที่เกมของคุณโหลดมีความยืดหยุ่นและเป็นโมดุลมากขึ้น (ดังนั้นทำไมวิธีการนั้นจึงเป็นแนวปฏิบัติที่ดีที่สุด)
jhocking

5

ฉันอยากจะแนะนำให้คุณสร้างอาร์เรย์ของเหตุการณ์โต้ตอบ แต่ละเหตุการณ์เป็นวัตถุที่มีข้อความที่ NPC พูดและอาร์เรย์ของการตอบสนองของผู้เล่นที่เป็นไปได้ซึ่งจะเป็นวัตถุที่มีข้อความตอบกลับและดัชนีของเหตุการณ์ที่ตามมาในการตอบสนองนี้

var event = []; // create empty array

// create event objects and store them in the array
event[0] = { text: "Hello, how are you?",
             options: [    { response: "Bad", next: 1 },
                           { response: "Good", next: 2 }
                      ]
           };
event[1] = { text: "Why, what's wrong?",
             options: [    { response: "My dog ran away", next: 3},
                           { response: "I broke up with my girlfriend", next: 4}
                      ]
           };
event[2] = { text: "That's nice",

...

2

คุณควรใช้วิธีการอื่น JavaScript รองรับอาร์เรย์และวัตถุดังนั้นทำไมไม่ใช้หนึ่งรายการต่อหนึ่งช่วยคุณแยกทั้งหมดและทำให้ข้อความจริงง่ายต่อการแก้ไข / อ่าน

หากคุณต้องการคุณสามารถมีลักษณะที่ต้นแบบบางผมได้ทำในช่วงไม่กี่ชั่วโมงสำหรับ# 1gam แหล่งที่มานั้นมีอิสระที่จะใช้ภายใต้ GPLv3 (ฉันดีมากถ้าคุณไม่ยึดติดกับ GPL ถ้าคุณแค่ใช้มันเพื่อเป็นแรงบันดาลใจ แต่แจ้งให้เราทราบเมื่อเกมของคุณเสร็จสิ้น) อย่าคาดหวังว่าจะได้งานเขียนที่ยอดเยี่ยมหรืออะไรทำนองนั้น ;)

ในการให้คำอธิบายสั้น ๆ เกี่ยวกับวิธีการทำงานของโค้ดให้ละเว้นสิ่งต่าง ๆ ที่เป็นภาพเคลื่อนไหว CSS และสิ่งต่างๆดังนี้:

  • var data โดยพื้นฐานแล้วประกอบด้วยเรื่องราวทั้งหมดพร้อมตัวเลือกที่เป็นไปได้ ฯลฯ
  • ID "ตำแหน่ง" (หรือหน้า / รายการ) ทุกรายการจะถูกระบุด้วย ID ID แรกในรายการคือstartที่สองcwaitฯลฯ
  • ทุกสถานที่มีองค์ประกอบที่จำเป็นสองประการ: คำบรรยายภาพและข้อความจริง ลิงค์สำหรับการตัดสินใจเขียนด้วยมาร์กอัปแบบ[target location:display text]ง่าย ๆ
  • "เวทย์มนตร์" ทั้งหมดกำลังเกิดขึ้นภายในnavigate(): ฟังก์ชั่นนี้ทำให้ลิงค์มาร์กอัปคลิกได้ยาก อีกหน่อยเพราะฉันจัดการข้อความคงที่สำหรับคนตายด้วย replace()ส่วนที่สำคัญมีสองสายแรกที่จะ
  • รายการสุดท้ายที่เป็นตัวเลือกจะกำหนดสีพื้นหลังใหม่เพื่อให้กลมกลืนกันเพื่อรองรับอารมณ์โดยรวมของเกม
  • แทนที่จะกำหนดสีเหล่านี้คุณสามารถเพิ่มลิงค์ที่ชี้ไปยังตำแหน่งอื่นได้ (หมายเหตุรหัสนี้ไม่ได้จัดการโดยรหัสของฉันมันเป็นความคิดที่จะแสดงให้เห็นถึงสิ่งนี้):

    'start': ['Waking up', 'You wake...', 'cwait:yell for help', 'cwait: wait a bit', 'clook: look around']

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.