วิธีสร้างเกมเสมือนจริงแบบผู้เล่นหลายคนแบบเรียลไทม์ (ตอนที่ 2)

เผยแพร่แล้ว: 2022-03-10
สรุปโดยย่อ ↬ ในบทช่วยสอนนี้ คุณจะเขียนกลไกของเกมสำหรับเกมเสมือนจริง ซึ่งมีความเกี่ยวข้องอย่างใกล้ชิดกับองค์ประกอบผู้เล่นหลายคนแบบเรียลไทม์ของเกม

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

คำอธิบายเกมที่นี่ตัดตอนมาจากส่วนแรกของซีรีส์: ผู้เล่นแต่ละคู่จะได้รับแหวนลูกกลม เป้าหมายคือการ "เปิด" ลูกกลมทั้งหมด โดยที่ลูกกลมจะ "เปิด" หากอยู่สูงและสว่าง ลูกกลมจะ "ปิด" ถ้ามันอยู่ต่ำกว่าและสลัว อย่างไรก็ตาม ลูกกลม "เด่น" บางลูกส่งผลกระทบต่อเพื่อนบ้าน: ถ้ามันเปลี่ยนสถานะ เพื่อนบ้านก็เปลี่ยนสถานะด้วย ผู้เล่น 2 สามารถควบคุมลูกกลมที่มีเลขคู่ได้ และผู้เล่นที่ 1 สามารถควบคุมลูกกลมที่มีเลขคี่ได้ สิ่งนี้บังคับให้ผู้เล่นทั้งสองร่วมมือกันไขปริศนา

8 ขั้นตอนในบทช่วยสอนนี้แบ่งออกเป็น 3 ส่วน:

  1. การเติมข้อมูลส่วนต่อประสานผู้ใช้ (ขั้นตอนที่ 1 และ 2)
  2. เพิ่มกลไกของเกม (ขั้นตอนที่ 3 ถึง 5)
  3. ตั้งค่าการสื่อสาร (ขั้นตอนที่ 6 ถึง 8)

ส่วนนี้จะจบลงด้วยการสาธิตการทำงานออนไลน์เต็มรูปแบบสำหรับทุกคนที่จะเล่น คุณจะใช้ A-Frame VR และส่วนขยาย A-Frame หลายรายการ

คุณสามารถค้นหาซอร์สโค้ดที่เสร็จแล้วได้ที่นี่

เกมผู้เล่นหลายคนที่เสร็จสิ้นแล้ว ซิงโครไนซ์กับไคลเอนต์หลายตัว
เกมผู้เล่นหลายคนที่เสร็จสิ้นแล้ว ซิงโครไนซ์กับไคลเอนต์หลายตัว (ตัวอย่างขนาดใหญ่)

1. เพิ่มตัวบ่งชี้ภาพ

ในการเริ่มต้น เราจะเพิ่มตัวบ่งชี้ที่มองเห็นได้ของ ID ของลูกโลก แทรกองค์ประกอบ VR a-text ลูกคนแรกของ #container-orb0 บน L36

 <a-entity ...> <a-text class="orb-id" opacity="0.25" rotation="0 -90 0" value="4" color="#FFF" scale="3 3 3" position="0 -2 -0.25" material="side:double"></a-text> ... <a-entity position...> ... </a-entity> </a-entity>

"การพึ่งพา" ของ orb คือ orb ที่จะสลับ เมื่อสลับ: ตัวอย่างเช่น บอกว่า orb 1 มีการอ้างอิง orbs 2 และ 3 ซึ่งหมายความว่าถ้า orb 1 ถูกสลับ orbs 2 และ 3 จะถูกสลับด้วย เราจะเพิ่มตัวบ่งชี้ที่มองเห็นได้ของการพึ่งพาดังต่อไปนี้โดยตรงหลังจาก .animation-position

 <a-animation class="animation-position" ... /> <a-text class="dep-right" opacity="0.25" rotation="0 -90 0" value="4" color="#FFF" scale="10 10 10" position="0 0 1" material="side:double" ></a-text> <a-text class="dep-left" opacity="0.25"rotation="0 -90 0" value="1" color="#FFF" scale="10 10 10" position="0 0 -3" material="side:double" ></a-text>

ตรวจสอบว่ารหัสของคุณตรงกับซอร์สโค้ดของเราสำหรับขั้นตอนที่ 1 ตอนนี้ orb ของคุณควรตรงกับสิ่งต่อไปนี้:

ลูกกลมที่มีตัวบ่งชี้ภาพสำหรับ ID ของลูกโลกและรหัสของลูกกลมที่จะเรียก
ลูกกลมที่มีตัวบ่งชี้ภาพสำหรับ ID ของลูกโลกและรหัสของลูกกลมที่จะเรียก (ตัวอย่างขนาดใหญ่)

นี่เป็นการสรุปตัวบ่งชี้ภาพเพิ่มเติมที่เราจะต้องมี ต่อไป เราจะเพิ่ม orb แบบไดนามิกให้กับฉาก VR โดยใช้เทมเพลต orb นี้

2. เพิ่ม Orbs แบบไดนามิก

ในขั้นตอนนี้ เราจะเพิ่ม orbs ตามข้อกำหนด JSON-esque ของระดับ ซึ่งช่วยให้เราสามารถระบุและสร้างระดับใหม่ได้อย่างง่ายดาย เราจะใช้ลูกกลมจากขั้นตอนสุดท้ายในตอนที่ 1 เป็นแม่แบบ

ในการเริ่มต้น ให้นำเข้า jQuery เนื่องจากจะทำให้การปรับเปลี่ยน DOM และทำให้การปรับเปลี่ยนฉาก VR ง่ายขึ้น หลังจากนำเข้า A-Frame แล้ว ให้เพิ่มข้อมูลต่อไปนี้ใน L8:

 <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>

ระบุระดับโดยใช้อาร์เรย์ อาร์เรย์จะมีตัวอักษรอ็อบเจ็กต์ที่เข้ารหัส "การพึ่งพา" ของแต่ละออร์บ ภายในแท็ก <head> ให้เพิ่มการกำหนดค่าระดับต่อไปนี้ :

 <script> var orbs = [ {left: 1, right: 4}, {}, {on: true}, {}, {on: true} ]; </script>

สำหรับตอนนี้ แต่ละออร์บสามารถพึ่งพา "ด้านขวา" ได้เพียงอันเดียว และอีกอันหนึ่งอยู่ที่ "ซ้าย" ของมัน ทันทีหลังจากประกาศ orbs ด้านบน ให้เพิ่มตัวจัดการที่จะทำงานเมื่อโหลดหน้าเว็บ ตัวจัดการนี้จะ (1) ทำซ้ำแม่แบบลูกโลกและ (2) ลบแม่แบบลูกโลกโดยใช้การกำหนดค่าระดับที่ให้มา:

 $(document).ready(function() { function populateTemplate(orb, template, i, total) {} function remove(selector) {} for (var i=0; i < orbs.length; i++) { var orb = orbs[i]; var template = $('#template').clone(); template = populateTemplate(orb, template, i, orbs.length); $('#carousel').append(template); } remove('#template'); } function clickOrb(i) {}

ถัดไป เติมฟังก์ชันการ remove ซึ่งเพียงแค่ลบรายการออกจากฉาก VR โดยให้ตัวเลือก โชคดีที่ A-Frame สังเกตเห็นการเปลี่ยนแปลงของ DOM ดังนั้นการนำรายการออกจาก DOM ก็เพียงพอแล้วที่จะนำออกจากฉาก VR เติมฟังก์ชันการ remove ดังนี้

 function remove(selector) { var el = document.querySelector(selector); el.parentNode.removeChild(el); }

เติมฟังก์ชัน clickOrb ซึ่งเพียงทริกเกอร์การดำเนินการคลิกบน orb

 function clickOrb(i) { document.querySelector("#container-orb" + i).click(); }

ถัดไป เริ่มเขียนฟังก์ชัน populateTemplate ในฟังก์ชันนี้ ให้เริ่มต้นด้วยการรับ . .container คอนเทนเนอร์สำหรับลูกกลมนี้ยังมีตัวบ่งชี้ที่มองเห็นได้ที่เราเพิ่มไว้ในขั้นตอนก่อนหน้านี้ นอกจากนี้ เราจะต้องแก้ไขพฤติกรรม onclick ของ orb ตามการพึ่งพา หากมีการพึ่งพาด้านซ้าย ให้แก้ไขทั้งตัวบ่งชี้ภาพและพฤติกรรม onclick เพื่อสะท้อนถึงสิ่งนั้น เช่นเดียวกับการพึ่งพาสิทธิ:

 function populateTemplate(orb, template, i, total) { var container = template.find('.container'); var onclick = 'document.querySelector("#light-orb' + i + '").emit("switch");'; if (orb.left || orb.right) { if (orb.left) { onclick += 'clickOrb(' + orb.left + ');'; container.find('.dep-left').attr('value', orb.left); } if (orb.right) { onclick += 'clickOrb(' + orb.right + ');'; container.find('.dep-right').attr('value', orb.right); } } else { container.find('.dep-left').remove(); container.find('.dep-right').remove(); } }

ยังอยู่ในฟังก์ชัน populateTemplate ให้ตั้งค่า orb ID อย่างถูกต้องในออร์บทั้งหมดและองค์ประกอบของคอนเทนเนอร์

 container.find('.orb-id').attr('value', i); container.attr('id', 'container-orb' + i); template.find('.orb').attr('id', 'orb' + i); template.find('.light-orb').attr('id', 'light-orb' + i); template.find('.clickable').attr('data-id', i);

ยังคงอยู่ในฟังก์ชัน populateTemplate ตั้งค่าพฤติกรรม onclick ตั้งค่าสุ่ม seed เพื่อให้แต่ละ orb แตกต่างกัน และสุดท้าย กำหนดตำแหน่งการหมุนของ orb ตาม ID

 container.attr('onclick', onclick); container.find('lp-sphere').attr('seed', i); template.attr('rotation', '0 ' + (360 / total * i) + ' 0');

ที่ส่วนท้ายของฟังก์ชัน ให้ส่งคืน template พร้อมการกำหนดค่าทั้งหมดข้างต้น

 return template;

ภายในตัวจัดการการโหลดเอกสารและหลังจากลบเทมเพลตด้วย remove('#template') แล้ว ให้เปิด orbs ที่ได้รับการกำหนดค่าให้เปิดใช้งานในตอนแรก

 $(document).ready(function() { ... setTimeout(function() { for (var i=0; i < orbs.length; i++) { var orb = orbs[i]; if (orb.on) { document.querySelector("#container-orb" + i).click(); } } }, 1000); });

นี่เป็นการสรุปการแก้ไขจาวาสคริปต์ ต่อไป เราจะเปลี่ยนการตั้งค่าเริ่มต้นของแม่แบบเป็นแบบลูกกลม 'ปิด' เปลี่ยนตำแหน่งและมาตราส่วนสำหรับ #container-orb0 เป็นดังต่อไปนี้:

 position="8 0.5 0" scale="0.5 0.5 0.5"

จากนั้น เปลี่ยนความเข้มของ #light-orb0 เป็น 0

 intensity="0"

ตรวจสอบว่าซอร์สโค้ดของคุณตรงกับซอร์สโค้ดของเราสำหรับขั้นตอนที่ 2

ฉาก VR ของคุณควรมี 5 orb ซึ่งบรรจุแบบไดนามิก ลูกกลมตัวใดตัวหนึ่งควรมีตัวบ่งชี้ที่มองเห็นได้ของการพึ่งพาเช่นด้านล่าง:

orb ทั้งหมดจะถูกเติมแบบไดนามิก โดยใช้เทมเพลต orb
ลูกกลมทั้งหมดจะถูกเติมแบบไดนามิก โดยใช้แม่แบบลูกโลก (ตัวอย่างขนาดใหญ่)

นี่เป็นการสรุปส่วนแรกในการเพิ่มลูกกลมแบบไดนามิก ในส่วนถัดไป เราจะใช้สามขั้นตอนในการเพิ่มกลไกของเกม โดยเฉพาะอย่างยิ่ง ผู้เล่นจะสามารถสลับเฉพาะ orbs ขึ้นอยู่กับ ID ผู้เล่นเท่านั้น

3. เพิ่มสถานะเทอร์มินัล

ในขั้นตอนนี้ เราจะเพิ่มสถานะเทอร์มินัล หากเปิดลูกแก้วทั้งหมดสำเร็จ ผู้เล่นจะเห็นหน้า "ชัยชนะ" ในการทำเช่นนี้ คุณจะต้องติดตามสถานะของลูกกลมทั้งหมด ทุกครั้งที่เปิดหรือปิด orb เราจะต้องอัปเดตสถานะภายในของเรา บอกว่าฟังก์ชั่นตัวช่วย toggleOrb อัปเดตสถานะสำหรับเรา เรียกใช้ฟังก์ชัน toggleOrb ทุกครั้งที่ orb เปลี่ยนสถานะ: (1) เพิ่มตัวฟังการคลิกไปยังตัวจัดการ onload และ (2) เพิ่ม toggleOrb(i); เรียกให้ clickOrb สุดท้าย (3) กำหนด toggleOrb ว่าง

 $(document).ready(function() { ... $('.orb').on('click', function() { var id = $(this).attr('data-id') toggleOrb(id); }); }); function toggleOrb(i) {} function clickOrb(i) { ... toggleOrb(i); }

เพื่อความง่าย เราจะใช้การกำหนดค่าระดับของเราเพื่อระบุสถานะของเกม ใช้ toggleOrb เพื่อสลับสถานะ on สำหรับ ith orb toggleOrb สามารถทริกเกอร์สถานะเทอร์มินัลเพิ่มเติมได้หากเปิด orbs ทั้งหมด

 function toggleOrb(i) { orbs[i].on = !orbs[i].on; if (orbs.every(orb => orb.on)) console.log('Victory!'); }

ตรวจสอบอีกครั้งว่าโค้ดของคุณตรงกับซอร์สโค้ดของเราสำหรับขั้นตอนที่ 3

นี่เป็นการสรุปโหมด "ผู้เล่นคนเดียว" สำหรับเกม ณ จุดนี้คุณมีเกมเสมือนจริงที่ทำงานได้อย่างสมบูรณ์ อย่างไรก็ตาม ตอนนี้คุณจะต้องเขียนองค์ประกอบผู้เล่นหลายคนและสนับสนุนการทำงานร่วมกันผ่านกลไกของเกม

4. สร้างวัตถุผู้เล่น

ในขั้นตอนนี้ เราจะสร้างสิ่งที่เป็นนามธรรมสำหรับผู้เล่นที่มี ID ผู้เล่น ID ผู้เล่นนี้จะถูกกำหนดโดยเซิร์ฟเวอร์ในภายหลัง

สำหรับตอนนี้ นี่จะเป็นตัวแปรส่วนกลาง หลังจากกำหนด orbs โดยตรง ให้กำหนด ID ผู้เล่น:

 var orbs = ... var current_player_id = 1;

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

5. สลับลูกกลมแบบมีเงื่อนไข

ในขั้นตอนนี้ เราจะปรับเปลี่ยนพฤติกรรมการสลับลูกโลก โดยเฉพาะ ผู้เล่น 1 สามารถควบคุมลูกกลมเลขคี่ และผู้เล่น 2 สามารถควบคุมลูกกลมเลขคู่ได้ ขั้นแรก ใช้ตรรกะนี้ในทั้งสองที่ซึ่ง orbs เปลี่ยนสถานะ:

 $('.orb').on('click', function() { var id = ... if (!allowedToToggle(id)) return false; ... } ... function clickOrb(i) { if (!allowedToToggle(id)) return; ... }

ประการที่สอง กำหนดฟังก์ชัน allowedToToggle ทันทีหลังจาก clickOrb หากผู้เล่นคนปัจจุบันคือผู้เล่นที่ 1 รหัสที่เป็นเลขคี่จะส่งกลับค่าความจริง-y ดังนั้น ผู้เล่นที่ 1 จะได้รับอนุญาตให้ควบคุมลูกกลมที่มีเลขคี่ สิ่งที่ตรงกันข้ามคือความจริงสำหรับผู้เล่น 2 ผู้เล่นอื่น ๆ ทั้งหมดไม่ได้รับอนุญาตให้ควบคุมลูกกลม

 function allowedToToggle(id) { if (current_player_id == 1) { return id % 2; } else if (current_player_id == 2) { return !(id % 2); } return false; }

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

ในส่วนถัดไป เราจะอำนวยความสะดวกในการสื่อสารระหว่างผู้เล่นทั้งสองผ่านเซิร์ฟเวอร์

6. ตั้งค่าเซิร์ฟเวอร์ด้วย WebSocket

ในขั้นตอนนี้ คุณจะตั้งค่าเซิร์ฟเวอร์อย่างง่ายเพื่อ (1) ติดตาม ID ผู้เล่นและ (2) ข้อความรีเลย์ ข้อความเหล่านี้จะรวมสถานะของเกม เพื่อให้ผู้เล่นมั่นใจได้ว่าแต่ละคนเห็นสิ่งที่อีกฝ่ายเห็น

เราจะอ้างถึง index.html ก่อนหน้าของคุณเป็นซอร์สโค้ดฝั่งไคลเอ็นต์ เราจะอ้างถึงรหัสในขั้นตอนนี้ว่าเป็นซอร์สโค้ดฝั่งเซิร์ฟเวอร์ ไปที่ glitch.com คลิกที่ "โครงการใหม่" ที่ด้านบนขวา และในเมนูดร็อปดาวน์ ให้คลิกที่ "hello-express"

จากแผงด้านซ้ายมือ เลือก “package.json” และเพิ่ม socket-io ในการ dependencies พจนานุกรม dependencies ของคุณควรตรงกับต่อไปนี้

 "dependencies": { "express": "^4.16.4", "socketio": "^1.0.0" },

จากแผงด้านซ้ายมือ ให้เลือก “index.js” และแทนที่เนื้อหาของไฟล์นั้นด้วย socket.io Hello World ขั้นต่ำดังต่อไปนี้:

 const express = require("express"); const app = express(); var http = require('http').Server(app); var io = require('socket.io')(http); /** * Run application on port 3000 */ var port = process.env.PORT || 3000; http.listen(port, function(){ console.log('listening on *:', port); });

ด้านบนตั้งค่า socket.io บนพอร์ต 3000 สำหรับแอปพลิเคชันด่วนพื้นฐาน ถัดไป กำหนดตัวแปรส่วนกลางสองตัว ตัวหนึ่งสำหรับรักษารายชื่อผู้เล่นที่ใช้งานอยู่ และอีกตัวสำหรับรักษา ID ผู้เล่นที่ไม่ได้กำหนดที่เล็กที่สุด

 /** * Maintain player IDs */ var playerIds = []; var smallestPlayerId = 1;

ถัดไป กำหนดฟังก์ชัน getPlayerId ซึ่งสร้าง ID ผู้เล่นใหม่และทำเครื่องหมาย ID ผู้เล่นใหม่ว่า "ถ่ายแล้ว" โดยเพิ่มลงในอาร์เรย์ playerIds โดยเฉพาะอย่างยิ่ง ฟังก์ชันจะทำเครื่องหมาย smallestPlayerId แล้วอัปเดต smallestPlayerId โดยค้นหาจำนวนเต็มที่ไม่ได้ถ่ายที่เล็กที่สุดถัดไป

 function getPlayerId() { var playerId = smallestPlayerId; playerIds.push(playerId); while (playerIds.includes(smallestPlayerId)) { smallestPlayerId++; } return playerId; }

กำหนดฟังก์ชัน removePlayer ซึ่งจะอัปเดตหมายเลขผู้เล่นที่ smallestPlayerId ตามนั้น และเพิ่ม playerId ที่ให้มาเพื่อให้ผู้เล่นคนอื่นใช้ ID นั้นได้

 function removePlayer(playerId) { if (playerId < smallestPlayerId) { smallestPlayerId = playerId; } var index = playerIds.indexOf(playerId); playerIds.splice(index, 1); }

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

 /** * Handle socket interactions */ io.on('connection', function(socket) { socket.on('newPlayer', function() { socket.playerId = getPlayerId(); console.log("new player: ", socket.playerId); socket.emit('playerId', socket.playerId); }); socket.on('disconnect', function() { if (socket.playerId === undefined) return; console.log("disconnected player: ", socket.playerId); removePlayer(socket.playerId); }); });

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

ในขั้นตอนต่อไป เราจะแก้ไขไคลเอนต์เพื่อรับและใช้ ID ผู้เล่นที่เซิร์ฟเวอร์ส่งออกมา

7. สมัคร ID ผู้เล่น

ในสองขั้นตอนถัดไป เราจะทำประสบการณ์ผู้เล่นหลายคนในเวอร์ชันพื้นฐานให้สมบูรณ์ ในการเริ่มต้น ให้ผสานรวมการกำหนดรหัสผู้เล่นฝั่งไคลเอ็นต์ โดยเฉพาะอย่างยิ่ง ลูกค้าแต่ละรายจะขอรหัสผู้เล่นจากเซิร์ฟเวอร์ กลับไปที่ index.html ฝั่งไคลเอ็นต์ที่เรากำลังดำเนินการในขั้นตอนที่ 4 และก่อนหน้านี้

นำเข้า socket.io ใน head ที่ L7:

 <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.1.1/socket.io.js"></script>

หลังจากตัวจัดการการโหลดเอกสาร ให้สร้างอินสแตนซ์ซ็อกเก็ตและปล่อยเหตุการณ์ newPlayer ในการตอบสนอง ฝั่งเซิร์ฟเวอร์จะสร้าง ID ผู้เล่นใหม่โดยใช้เหตุการณ์ playerId ด้านล่างนี้ ใช้ URL สำหรับการแสดงตัวอย่างโปรเจ็กต์ Glitch แทน lightful.glitch.me คุณสามารถใช้ URL สาธิตด้านล่างได้ แต่การเปลี่ยนแปลงโค้ดใดๆ ที่คุณทำจะไม่มีผลแน่นอน

 $(document).ready(function() { ... }); socket = io("https://lightful.glitch.me"); socket.emit('newPlayer'); socket.on('playerId', function(player_id) { current_player_id = player_id; console.log(" * You are now player", current_player_id); });

ตรวจสอบว่ารหัสของคุณตรงกับซอร์สโค้ดของเราสำหรับขั้นตอนที่ 7 ตอนนี้คุณสามารถโหลดเกมของคุณบนเบราว์เซอร์หรือแท็บที่แตกต่างกันสองแบบเพื่อเล่นเกมแบบผู้เล่นหลายคนได้ทั้งสองด้าน ผู้เล่น 1 จะสามารถควบคุมลูกกลมที่มีเลขคี่ได้ และผู้เล่นที่ 2 จะสามารถควบคุมลูกกลมที่มีเลขคู่ได้

อย่างไรก็ตาม โปรดทราบว่าการสลับ orb สำหรับผู้เล่น 1 จะไม่ส่งผลต่อสถานะ orb สำหรับผู้เล่น 2 ต่อไป เราต้องซิงโครไนซ์สถานะของเกม

8. ซิงโครไนซ์สถานะเกม

ในขั้นตอนนี้ เราจะซิงโครไนซ์สถานะเกมเพื่อให้ผู้เล่น 1 และ 2 เห็นสถานะลูกโลกเดียวกัน หาก orb 1 เปิดสำหรับผู้เล่น 1 ก็ควรจะเปิดสำหรับผู้เล่น 2 ด้วย ในฝั่งไคลเอ็นต์ เราทั้งคู่จะประกาศและฟังการสลับลูกโลก ในการประกาศ เราจะเพียงแค่ส่ง ID ของ orb ที่ถูกสลับ

ก่อนการเรียก toggleOrb ทั้งสอง ให้เพิ่มการเรียก socket.emit ต่อไปนี้

 $(document).ready(function() { ... $('.orb').on('click', function() { ... socket.emit('toggleOrb', id); toggleOrb(id); }); }); ... function clickOrb(i) { ... socket.emit('toggleOrb', i); toggleOrb(i); }

ถัดไป ฟังการสลับลูกโลก และสลับลูกโลกที่เกี่ยวข้อง ตรงข้างใต้ตัวฟังเหตุการณ์ซ็อกเก็ต playerId เพิ่มตัวฟังอื่นสำหรับเหตุการณ์ toggleOrb

 socket.on('toggleOrb', function(i) { document.querySelector("#container-orb" + i).click(); toggleOrb(i); });

การดำเนินการนี้เป็นการสรุปการแก้ไขโค้ดฝั่งไคลเอ็นต์ ตรวจสอบอีกครั้งว่าโค้ดของคุณตรงกับซอร์สโค้ดของเราสำหรับขั้นตอนที่ 8

ฝั่งเซิร์ฟเวอร์ต้องรับและเผยแพร่รหัส orb ที่สลับแล้ว ใน index.js ฝั่งเซิร์ฟเวอร์ ให้เพิ่มฟังต่อไปนี้ ตัวฟังนี้ควรวางไว้ใต้ตัวฟังที่ disconnect ซ็อกเก็ตโดยตรง

 socket.on('toggleOrb', function(i) { socket.broadcast.emit('toggleOrb', i); });

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

เกมผู้เล่นหลายคนที่เสร็จสิ้นแล้ว ซิงโครไนซ์กับไคลเอนต์หลายตัว
เกมผู้เล่นหลายคนที่เสร็จสิ้นแล้ว ซิงโครไนซ์กับไคลเอนต์หลายตัว (ตัวอย่างขนาดใหญ่)

บทสรุป

นี่เป็นการสรุปบทช่วยสอนของเราเกี่ยวกับการสร้างเกมเสมือนจริงที่มีผู้เล่นหลายคน ในกระบวนการนี้ คุณได้กล่าวถึงหัวข้อต่างๆ มากมาย รวมถึงการสร้างแบบจำลอง 3 มิติใน A-Frame VR และประสบการณ์ผู้เล่นหลายคนแบบเรียลไทม์โดยใช้ WebSockets

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

ด้วยกรอบการทำงานที่เราได้กำหนดขึ้นและแนวความคิดที่เราได้แนะนำ ตอนนี้คุณมีเครื่องมือในการตอบคำถามเหล่านี้และสร้างเพิ่มเติมอีกมาก

คุณสามารถค้นหาซอร์สโค้ดที่เสร็จแล้วได้ที่นี่

เพิ่มเติมหลังกระโดด! อ่านต่อด้านล่าง↓