วิธีสร้างเกมเสมือนจริงแบบผู้เล่นหลายคนแบบเรียลไทม์ (ตอนที่ 2)
เผยแพร่แล้ว: 2022-03-10ในซีรีส์บทช่วยสอนนี้ เราจะสร้างเกมเสมือนจริงแบบผู้เล่นหลายคนบนเว็บ ซึ่งผู้เล่นจะต้องร่วมมือกันไขปริศนา ในส่วนแรกของซีรีส์นี้ เราได้ออกแบบลูกกลมที่มีในเกม ในส่วนนี้ของซีรีส์ เราจะเพิ่มกลไกของเกมและตั้งค่าโปรโตคอลการสื่อสารระหว่างผู้เล่นเป็นคู่
คำอธิบายเกมที่นี่ตัดตอนมาจากส่วนแรกของซีรีส์: ผู้เล่นแต่ละคู่จะได้รับแหวนลูกกลม เป้าหมายคือการ "เปิด" ลูกกลมทั้งหมด โดยที่ลูกกลมจะ "เปิด" หากอยู่สูงและสว่าง ลูกกลมจะ "ปิด" ถ้ามันอยู่ต่ำกว่าและสลัว อย่างไรก็ตาม ลูกกลม "เด่น" บางลูกส่งผลกระทบต่อเพื่อนบ้าน: ถ้ามันเปลี่ยนสถานะ เพื่อนบ้านก็เปลี่ยนสถานะด้วย ผู้เล่น 2 สามารถควบคุมลูกกลมที่มีเลขคู่ได้ และผู้เล่นที่ 1 สามารถควบคุมลูกกลมที่มีเลขคี่ได้ สิ่งนี้บังคับให้ผู้เล่นทั้งสองร่วมมือกันไขปริศนา
8 ขั้นตอนในบทช่วยสอนนี้แบ่งออกเป็น 3 ส่วน:
- การเติมข้อมูลส่วนต่อประสานผู้ใช้ (ขั้นตอนที่ 1 และ 2)
- เพิ่มกลไกของเกม (ขั้นตอนที่ 3 ถึง 5)
- ตั้งค่าการสื่อสาร (ขั้นตอนที่ 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 ของคุณควรตรงกับสิ่งต่อไปนี้:

นี่เป็นการสรุปตัวบ่งชี้ภาพเพิ่มเติมที่เราจะต้องมี ต่อไป เราจะเพิ่ม 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 ซึ่งบรรจุแบบไดนามิก ลูกกลมตัวใดตัวหนึ่งควรมีตัวบ่งชี้ที่มองเห็นได้ของการพึ่งพาเช่นด้านล่าง:

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