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

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

ความเป็นจริงเสมือน (VR) เป็นประสบการณ์ในสภาพแวดล้อมที่สร้างด้วยคอมพิวเตอร์ ผลิตภัณฑ์ VR ที่แตกต่างกันจำนวนหนึ่งสร้างหัวข้อข่าวและการใช้งานที่หลากหลาย: สำหรับโอลิมปิกฤดูหนาว ทีมงานของสหรัฐฯ ใช้ความเป็นจริงเสมือนสำหรับการฝึกกีฬา ศัลยแพทย์กำลังทดลองกับความเป็นจริงเสมือนสำหรับการฝึกอบรมทางการแพทย์ และโดยทั่วไปแล้ว ความเป็นจริงเสมือนจะถูกนำไปใช้กับเกม

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

การพัฒนาเพื่อความเป็นจริงเสมือน

นักพัฒนาทุกคนสามารถสร้างเนื้อหาสำหรับ VR ได้ในปัจจุบัน เพื่อให้เข้าใจการพัฒนา VR มากขึ้น การทำโปรเจ็กต์สาธิตสามารถช่วยได้ อ่านบทความที่เกี่ยวข้อง →

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

ข้อกำหนดเบื้องต้น

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

  • การเข้าถึงอินเทอร์เน็ต โดยเฉพาะกับ glitch.com
  • ชุดหูฟังเสมือนจริง (แนะนำเสริม) ฉันใช้ Google Cardboard ซึ่งเสนอราคา 15 ดอลลาร์ต่อชิ้น
เพิ่มเติมหลังกระโดด! อ่านต่อด้านล่าง↓

ขั้นตอนที่ 1: การตั้งค่าแบบจำลองเสมือนจริง (VR)

ในขั้นตอนนี้ เราจะสร้างเว็บไซต์ที่มีหน้า HTML แบบคงที่หน้าเดียว ซึ่งช่วยให้เราสามารถเขียนโค้ดจากเดสก์ท็อปของคุณและปรับใช้กับเว็บได้โดยอัตโนมัติ เว็บไซต์ที่ปรับใช้แล้วสามารถโหลดบนโทรศัพท์มือถือของคุณและวางไว้ในชุดหูฟัง VR เว็บไซต์ที่ปรับใช้สามารถโหลดได้ด้วยชุดหูฟัง VR แบบสแตนด์อโลน เริ่มต้นโดยไปที่ glitch.com แล้ว,

  1. คลิกที่ "โครงการใหม่" ที่ด้านบนขวา
  2. คลิกที่ "สวัสดีด่วน" ในเมนูแบบเลื่อนลง
เริ่มต้นโดยไปที่ glitch.com
(ตัวอย่างขนาดใหญ่)

จากนั้น ให้คลิกที่ views/index.html ในแถบด้านข้างทางซ้าย เราจะเรียกสิ่งนี้ว่า "บรรณาธิการ" ของคุณ

ขั้นตอนต่อไปคือการคลิกที่ views/index.html ในแถบด้านข้างทางซ้าย ซึ่งจะเรียกว่า "ตัวแก้ไข" ของคุณ
(ตัวอย่างขนาดใหญ่)

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

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

กลับไปที่โปรแกรมแก้ไขของคุณ แทนที่ HTML ปัจจุบันด้วยต้นแบบต่อไปนี้สำหรับโมเดล VR

 <!DOCTYPE html> <html> <head> <script src="https://aframe.io/releases/0.7.0/aframe.min.js"></script> </head> <body> <a-scene> <!-- blue sky --> <a-sky color="#a3d0ed"></a-sky> <!-- camera with wasd and panning controls --> <a-entity camera look-controls wasd-controls position="0 0.5 2" rotation="0 0 0"></a-entity> <!-- brown ground --> <a-box shadow shadow="receive:true" color="#847452" width="10" height="0.1" depth="10"></a-box> <!-- start code here --> <!-- end code here --> </a-scene> </body> </html>

นำทางดูต่อไปนี้

เมื่อย้อนกลับไปยังหน้าตัวอย่าง คุณจะเห็นสีพื้นสนามเป็นสีน้ำเงินและน้ำตาล
(ตัวอย่างขนาดใหญ่)

หากต้องการดูตัวอย่างบนชุดหูฟัง VR ให้ใช้ URL ในแถบอเนกประสงค์ ในภาพด้านบน URL คือ https://point-and-click-vr-game.glitch.me/ สภาพแวดล้อมการทำงานของคุณได้รับการตั้งค่าแล้ว อย่าลังเลที่จะแบ่งปัน URL นี้กับครอบครัวและเพื่อน ๆ ในขั้นตอนต่อไป คุณจะต้องสร้างแบบจำลองความเป็นจริงเสมือน

ขั้นตอนที่ 2: สร้างแบบจำลองต้นไม้

ตอนนี้คุณจะสร้างต้นไม้โดยใช้ primitives จาก aframe.io สิ่งเหล่านี้เป็นอ็อบเจ็กต์มาตรฐานที่ Aframe ตั้งโปรแกรมไว้ล่วงหน้าเพื่อความสะดวกในการใช้งาน โดยเฉพาะอย่างยิ่ง Aframe หมายถึงอ็อบเจ็กต์เป็น เอนทิตี มีสามแนวคิดที่เกี่ยวข้องกับหน่วยงานทั้งหมด เพื่อจัดระเบียบการอภิปรายของเรา:

  1. เรขาคณิตและวัสดุ
  2. แกนแปลงร่าง,
  3. การเปลี่ยนแปลงสัมพัทธ์

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

Aframe ทำให้แนวคิดนี้ง่ายขึ้นโดยการกำหนดพื้นฐาน เช่น <a-box> , <a-sphere> , <a-cylinder> และอื่นๆ เพื่อทำให้ข้อกำหนดของเรขาคณิตและวัสดุง่ายขึ้น เริ่มต้นด้วยการกำหนดทรงกลมสีเขียว ในบรรทัดที่ 19 ในโค้ดของคุณ ต่อจาก <!-- start code here --> ให้เพิ่มสิ่งต่อไปนี้

 <!-- start code here --> <a-sphere color="green" radius="0.5"></a-sphere> <!-- new line --> <!-- end code here -->

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

ตัวอย่างเช่น ในการแปลวัตถุ "ถูกต้อง" เราจะเพิ่มค่า x ของวัตถุนั้น หากต้องการหมุนวัตถุให้เหมือนยอด เราหมุนวัตถุนั้นไปตามแกน y แก้ไขบรรทัดที่ 19 เพื่อย้ายทรงกลม "ขึ้น" ซึ่งหมายความว่าคุณต้องเพิ่มค่า y ของทรงกลม โปรดทราบว่าการแปลงทั้งหมดถูกระบุเป็น <x> <y> <z> ซึ่งหมายความว่าหากต้องการเพิ่มค่า y คุณต้องเพิ่มค่าที่สอง โดยค่าเริ่มต้น วัตถุทั้งหมดจะอยู่ที่ตำแหน่ง 0, 0, 0 เพิ่มข้อกำหนด position ด้านล่าง

 <!-- start code here --> <a-sphere color="green" radius="0.5" position="0 1 0"></a-sphere> <!-- edited line --> <!-- end code here -->

ประการที่สาม การแปลงทั้งหมด สัมพันธ์ กับระดับบนสุด ในการเพิ่มลำต้นให้กับต้นไม้ของคุณ ให้เพิ่มทรงกระบอกภายในทรงกลมด้านบน เพื่อให้แน่ใจว่าตำแหน่งของลำตัวของคุณสัมพันธ์กับตำแหน่งของทรงกลม โดยพื้นฐานแล้วสิ่งนี้จะทำให้ต้นไม้ของคุณรวมกันเป็นหนึ่งเดียว เพิ่มเอนทิตี <a-cylinder> ระหว่างแท็ก <a-sphere ...> และ </a-sphere>

 <a-sphere color="green" radius="0.5" position="0 1 0"> <a-cylinder color="#84651e" position="0 -0.9 0" radius="0.05"></a-cylinder> <!-- new line --> </a-sphere>

ในการสร้างแบร์โบนที่ไร้ต้นไม้นี้ ให้เพิ่มใบไม้ให้มากขึ้น ในรูปของทรงกลมสีเขียวอีกสองลูก

 <a-sphere color="green" radius="0.5" position="0 0.75 0"> <a-cylinder color="#84651e" position="0 -0.9 0" radius="0.05"></a-cylinder> <a-sphere color="green" radius="0.35" position="0 0.5 0"></a-sphere> <!-- new line --> <a-sphere color="green" radius="0.2" position="0 0.8 0"></a-sphere> <!-- new line --> </a-sphere>

กลับไปที่การแสดงตัวอย่างของคุณ แล้วคุณจะเห็นแผนผังต่อไปนี้:

เมื่อย้อนกลับไปยังการแสดงตัวอย่าง คุณจะสามารถเห็นต้นไม้สีเขียววางอยู่ในพื้นหลังของคุณ
(ตัวอย่างขนาดใหญ่)

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

ขั้นตอนที่ 3: เพิ่มการโต้ตอบคลิกไปที่โมเดล

ในการทำให้เอนทิตีโต้ตอบได้ คุณจะต้อง:

  • เพิ่มแอนิเมชั่น,
  • มีแอนิเมชั่นทริกเกอร์เมื่อคลิก

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

 <a-entity camera look-controls wasd-controls position="0 0.5 2" rotation="0 0 0"> <a-entity cursor="fuse: true; fuseTimeout: 250" position="0 0 -1" geometry="primitive: ring; radiusInner: 0.02; radiusOuter: 0.03" material="color: black; shader: flat" scale="0.5 0.5 0.5" raycaster="far: 20; interval: 1000; objects: .clickable"> <!-- add animation here --> </a-entity> </a-entity>

ด้านบนเพิ่มเคอร์เซอร์ที่สามารถเรียกการกระทำการคลิก สังเกต objects: .clickable ซึ่งหมายความว่าวัตถุทั้งหมดที่มีคลาส "คลิกได้" จะทริกเกอร์ภาพเคลื่อนไหวและรับคำสั่ง "คลิก" ตามความเหมาะสม คุณจะเพิ่มแอนิเมชั่นให้กับเคอร์เซอร์การคลิกด้วย เพื่อให้ผู้ใช้ทราบเมื่อเคอร์เซอร์ทริกเกอร์การคลิก ในที่นี้ เคอร์เซอร์จะหดตัวช้าๆ เมื่อชี้ไปที่วัตถุที่คลิกได้ โดยสแนปหลังจากผ่านไปหนึ่งวินาทีเพื่อแสดงว่ามีการคลิกวัตถุ แทนที่ความคิดเห็น <!-- add animation here --> ด้วยรหัสต่อไปนี้:

 <a-animation begin="fusing" easing="ease-in" attribute="scale" fill="backwards" from="1 1 1" to="0.2 0.2 0.2" dur="250"></a-animation>

ย้ายต้นไม้ไปทางขวา 2 หน่วยและเพิ่มคลาส "คลิกได้" ให้กับต้นไม้โดยแก้ไขบรรทัดที่ 29 เพื่อให้ตรงกับต่อไปนี้

 <a-sphere color="green" radius="0.5" position="2 0.75 0" class="clickable">

ถัดไป คุณจะ:

  • ระบุภาพเคลื่อนไหว
  • เรียกภาพเคลื่อนไหวด้วยการคลิก

เนื่องจากเอนทิตีแอนิเมชั่นที่ใช้งานง่ายของ Aframe ทั้งสองขั้นตอนจึงสามารถทำได้อย่างรวดเร็ว

เพิ่มแท็ก <a-animation> ในบรรทัดที่ 33 ต่อจากแท็ก <a-cylinder> แต่ก่อนสิ้นสุด </a-sphere>

 <a-animation begin="click" attribute="position" from="2 0.75 0" to="2.2 0.75 0" fill="both" direction="alternate" repeat="1"></a-animation>

คุณสมบัติข้างต้นระบุการกำหนดค่าจำนวนหนึ่งสำหรับแอนิเมชั่น แอนิเมชั่น:

  • ถูกเรียกโดยเหตุการณ์การ click
  • ปรับเปลี่ยน position ของต้นไม้
  • เริ่มจากตำแหน่งเดิม 2 0.75 0
  • สิ้นสุดใน 2.2 0.75 0 (เคลื่อนที่ไปทางขวา 0.2 หน่วย)
  • เคลื่อนไหวเมื่อเดินทางไปและกลับจากปลายทาง
  • สลับภาพเคลื่อนไหวระหว่างการเดินทางไปและกลับจากปลายทาง
  • เล่นแอนิเมชั่นนี้ซ้ำ 1 ครั้ง ซึ่งหมายความว่าวัตถุจะเคลื่อนไหวทั้งหมดสองครั้ง — หนึ่งครั้งไปยังปลายทางและอีกครั้งหนึ่งกลับสู่ตำแหน่งเดิม

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

เมื่อวงกลมสีดำวางอยู่บนต้นไม้ ต้นไม้จะเคลื่อนไปทางขวาและด้านหลัง
ตัวอย่างขนาดใหญ่

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

ภารกิจคือการเปิดประตูและซ่อนต้นไม้หลังประตูโดยคลิกที่วัตถุต่างๆในฉาก
(ตัวอย่างขนาดใหญ่)

ต่อไป เราตั้งค่าเซิร์ฟเวอร์ nodeJS อย่างง่ายเพื่อให้บริการการสาธิตแบบคงที่ของเรา

ขั้นตอนที่ 4: ตั้งค่าเซิร์ฟเวอร์ NodeJS

ในขั้นตอนนี้ เราจะตั้งค่าเซิร์ฟเวอร์ nodeJS พื้นฐานที่ใช้งานได้ซึ่งให้บริการโมเดล VR ที่คุณมีอยู่ ในแถบด้านข้างทางซ้ายของเอดิเตอร์ เลือก package.json

เริ่มต้นด้วยการลบบรรทัด 2-4

 "//1": "describes your app and its dependencies", "//2": "https://docs.npmjs.com/files/package.json", "//3": "updating this file will download and update your packages",

เปลี่ยนชื่อเป็น mirrorvr

 { "name": "mirrorvr", // change me "version": "0.0.1", ...

ภายใต้ dependencies ให้เพิ่ม socket.io

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

อัปเดต URL ที่เก็บให้ตรงกับความผิดพลาดในปัจจุบันของคุณ ตัวอย่างโปรเจ็กต์ผิดพลาดมีชื่อว่า point-and-click-vr-game แทนที่ด้วยชื่อโครงการผิดพลาดของคุณ

 "repository": { "url": "https://glitch.com/edit/#!/point-and-click-vr-game" },

สุดท้าย เปลี่ยนแท็ก "glitch" เป็น "vr"

 "keywords": [ "node", "vr", // change me "express" ]

ตรวจสอบอีกครั้งว่า package.json ของคุณตรงกับรายการต่อไปนี้

 { "name": "mirrorvr", "version": "0.0.1", "description": "Mirror virtual reality models", "main": "server.js", "scripts": { "start": "node server.js" }, "dependencies": { "express": "^4.16.3", "socketio": "^1.0.0" }, "engines": { "node": "8.x" }, "repository": { "url": "https://glitch.com/edit/#!/point-and-click-vr-game" }, "license": "MIT", "keywords": [ "node", "vr", "express" ] }

ตรวจสอบอีกครั้งว่ารหัสของคุณจากส่วนก่อนหน้านี้ตรงกับสิ่งต่อไปนี้ใน views/index.html

 <!DOCTYPE html> <html> <head> <script src="https://aframe.io/releases/0.7.0/aframe.min.js"></script> </head> <body> <a-scene> <!-- blue sky --> <a-sky color="#a3d0ed"></a-sky> <!-- camera with wasd and panning controls --> <a-entity camera look-controls wasd-controls position="0 0.5 2" rotation="0 0 0"> <a-entity cursor="fuse: true; fuseTimeout: 250" position="0 0 -1" geometry="primitive: ring; radiusInner: 0.02; radiusOuter: 0.03" material="color: black; shader: flat" scale="0.5 0.5 0.5" raycaster="far: 20; interval: 1000; objects: .clickable"> <a-animation begin="fusing" easing="ease-in" attribute="scale" fill="backwards" from="1 1 1" to="0.2 0.2 0.2" dur="250"></a-animation> </a-entity> </a-entity> <!-- brown ground --> <a-box shadow shadow="receive:true" color="#847452" width="10" height="0.1" depth="10"></a-box> <!-- start code here --> <a-sphere color="green" radius="0.5" position="2 0.75 0" class="clickable"> <a-cylinder color="#84651e" position="0 -0.9 0" radius="0.05"></a-cylinder> <a-sphere color="green" radius="0.35" position="0 0.5 0"></a-sphere> <a-sphere color="green" radius="0.2" position="0 0.8 0"></a-sphere> <a-animation begin="click" attribute="position" from="2 0.75 0" to="2.2 0.75 0" fill="both" direction="alternate" repeat="1"></a-animation> </a-sphere> <!-- end code here --> </a-scene> </body> </html>

แก้ไข server.js ที่มีอยู่

เริ่มต้นด้วยการนำเข้ายูทิลิตี้ NodeJS หลายรายการ

  • ด่วน
    นี่คือกรอบงานเว็บที่เราจะใช้เพื่อเรียกใช้เซิร์ฟเวอร์
  • http
    สิ่งนี้ทำให้เราสามารถเรียกใช้ daemon เพื่อฟังกิจกรรมบนพอร์ตต่างๆ
  • socket.io
    การใช้งานซ็อกเก็ตที่ช่วยให้เราสามารถสื่อสารระหว่างฝั่งไคลเอ็นต์และฝั่งเซิร์ฟเวอร์ได้แบบเรียลไทม์

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

 var express = require('express'); var app = express(); /* start new code */ var http = require('http').Server(app); var io = require('socket.io')(http); /* end new code */ // we've started you off with Express,

เมื่อโหลดยูทิลิตี้แล้ว เซิร์ฟเวอร์ที่ให้มาในครั้งต่อไปจะแนะนำให้เซิร์ฟเวอร์ส่งคืน index.html เป็นโฮมเพจ โปรดทราบว่าไม่มีโค้ดใหม่เขียนไว้ด้านล่าง นี่เป็นเพียงคำอธิบายของซอร์สโค้ดที่มีอยู่

 // https://expressjs.com/en/starter/basic-routing.html app.get('/', function(request, response) { response.sendFile(__dirname + '/views/index.html'); });

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

 // listen for requests :) var listener = app.listen(process.env.PORT, function() { console.log('Your app is listening on port ' + listener.address().port); });

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

เว็บแอปพลิเคชันของคุณเริ่มทำงานแล้ว ต่อไป เราจะส่งข้อความจากลูกค้าไปยังเซิร์ฟเวอร์

ขั้นตอนที่ 5: ส่งข้อมูลจากลูกค้าไปยังเซิร์ฟเวอร์

ในขั้นตอนนี้ เราจะใช้ไคลเอนต์เพื่อเริ่มต้นการเชื่อมต่อกับเซิร์ฟเวอร์ ลูกค้าจะแจ้งเซิร์ฟเวอร์เพิ่มเติมว่าเป็นโทรศัพท์หรือเดสก์ท็อป ในการเริ่มต้น ให้นำเข้าไฟล์ Javascript ที่จะมีอยู่เร็วๆ นี้ใน views/index.html ของคุณ

หลังบรรทัดที่ 4 ให้รวมสคริปต์ใหม่

 <script src="/client.js" type="text/javascript"></script>

ในบรรทัดที่ 14 เพิ่ม camera-listener ในรายการคุณสมบัติสำหรับเอนทิตีของกล้อง

 <a-entity camera-listener camera look-controls...> ... </a-entity>

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

 /** * Check if client is on mobile */ function mobilecheck() { var check = false; (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[aw])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera); return check; };

ต่อไป เราจะกำหนดชุดข้อความเริ่มต้นเพื่อแลกเปลี่ยนกับฝั่งเซิร์ฟเวอร์ กำหนดอ็อบเจ็กต์ socket.io ใหม่เพื่อแสดงการเชื่อมต่อของไคลเอ็นต์กับเซิร์ฟเวอร์ เมื่อซ็อกเก็ตเชื่อมต่อแล้ว ให้บันทึกข้อความไปยังคอนโซล

 var socket = io(); socket.on('connect', function() { console.log(' * Connection established'); });

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

 if (mobilecheck()) { socket.emit('newHost'); } else { socket.emit('newMirror'); }

นี้สรุปการส่งข้อความของลูกค้า ตอนนี้ แก้ไขรหัสเซิร์ฟเวอร์เพื่อรับข้อความนี้และตอบสนองอย่างเหมาะสม เปิดไฟล์เซิร์ฟเวอร์ server.js

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

 /** * Handle socket interactions */ io.on('connection', function(socket) { socket.on('newMirror', function() { console.log(" * Participant registered as 'mirror'") }); socket.on('newHost', function() { console.log(" * Participant registered as 'host'"); }); });

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

 listening on *: 3000 * Participant registered as 'host' * Participant registered as 'mirror'

นี่เป็นครั้งแรกของการส่งข้อความธรรมดา โดยที่ลูกค้าของเราส่งข้อมูลกลับไปยังเซิร์ฟเวอร์ ออกจากกระบวนการ NodeJS ที่กำลังทำงานอยู่ สำหรับส่วนสุดท้ายของขั้นตอนนี้ เราจะให้ไคลเอนต์ส่งข้อมูลกล้องกลับไปที่เซิร์ฟเวอร์ เปิด public/client.js

ที่ส่วนท้ายสุดของไฟล์ ให้รวมสิ่งต่อไปนี้

 var camera; if (mobilecheck()) { AFRAME.registerComponent('camera-listener', { tick: function () { camera = this.el.sceneEl.camera.el; var position = camera.getAttribute('position'); var rotation = camera.getAttribute('rotation'); socket.emit('onMove', { "position": position, "rotation": rotation }); } }); }

บันทึกและปิด เปิดไฟล์เซิร์ฟเวอร์ของคุณ server.js เพื่อฟังเหตุการณ์ onMove นี้

เพิ่มสิ่งต่อไปนี้ในบล็อก newHost ของรหัสซ็อกเก็ตของคุณ

 socket.on('newHost', function() { console.log(" * Participant registered as 'host'"); /* start new code */ socket.on('onMove', function(data) { console.log(data); }); /* end new code */ });

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

ขั้นตอนที่ 6: ส่งข้อมูลจากเซิร์ฟเวอร์ไปยังไคลเอนต์

ในขั้นตอนนี้ คุณจะส่งข้อมูลกล้องของโฮสต์ไปยังมิเรอร์ทั้งหมด เปิดไฟล์เซิร์ฟเวอร์หลักของคุณ server.js

เปลี่ยนตัวจัดการเหตุการณ์ onMove เป็นดังต่อไปนี้:

 socket.on('onMove', function(data) { console.log(data); // delete me socket.broadcast.emit('move', data) });

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

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

 if (!mobilecheck()) { socket.on('move', function(data) { console.log(data); }); }

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

เปิดสคริปต์ไคลเอ็นต์อีกครั้งที่ public/client.js ในที่สุด เราก็ปรับกล้องไคลเอนต์ตามข้อมูลที่ส่ง

แก้ไขตัวจัดการเหตุการณ์ด้านบนสำหรับเหตุการณ์การ move

 socket.on('move', function(data) { /* start new code */ camera.setAttribute('rotation', data["rotation"]); camera.setAttribute('position', data["position"]); /* end new code */ });

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

บทสรุป

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

แนวคิดเหล่านี้ขยายไปไกลกว่าแม้แต่ webVR เนื่องจากแนวคิดเรื่องเรขาคณิตและวัสดุขยายไปถึง SceneKit บน iOS (ซึ่งเกี่ยวข้องกับ ARKit), Three.js (แกนหลักสำหรับ Aframe) และไลบรารีสามมิติอื่นๆ บล็อคการสร้างที่เรียบง่ายเหล่านี้ทำให้เรามีความยืดหยุ่นเพียงพอในการสร้างเกมผจญภัยแบบชี้แล้วคลิกที่สมบูรณ์ ที่สำคัญกว่านั้นคือช่วยให้เราสามารถสร้างเกมที่มีอินเทอร์เฟซแบบคลิกได้

ต่อไปนี้คือแหล่งข้อมูลและตัวอย่างต่างๆ ให้สำรวจเพิ่มเติม:

  • MirrorVR
    การนำไปใช้อย่างเต็มรูปแบบของการแสดงตัวอย่างสดที่สร้างขึ้นด้านบน ด้วยลิงก์ Javascript เพียงลิงก์เดียว คุณสามารถเพิ่มตัวอย่างแบบสดของโมเดล Virtual Reality บนมือถือลงในเดสก์ท็อปได้
  • ทีละนิด
    แกลเลอรีภาพวาดของเด็ก ๆ และแบบจำลองเสมือนจริงของแต่ละรูปวาดที่เกี่ยวข้อง
  • Aframe
    ตัวอย่าง เอกสารสำหรับนักพัฒนา และทรัพยากรเพิ่มเติมสำหรับการพัฒนาความเป็นจริงเสมือน
  • ประสบการณ์ Google Cardboard
    ประสบการณ์ในห้องเรียนด้วยเครื่องมือที่กำหนดเองสำหรับนักการศึกษา

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