วิธีสร้างเกมวิ่งที่ไม่มีที่สิ้นสุดในความเป็นจริงเสมือน (ตอนที่ 2)
เผยแพร่แล้ว: 2022-03-10ในตอนที่ 1 ของซีรีส์นี้ เราได้เห็นแล้วว่าสามารถสร้างแบบจำลองเสมือนจริงพร้อมเอฟเฟกต์แสงและแอนิเมชั่นได้อย่างไร ในส่วนนี้ เราจะใช้ตรรกะหลักของเกมและใช้การปรับแต่งสภาพแวดล้อม A-Frame ขั้นสูงเพื่อสร้างส่วน "เกม" ของแอปพลิเคชันนี้ ในตอนท้ายคุณจะมีเกมเสมือนจริงที่ใช้งานได้จริงพร้อมความท้าทายที่แท้จริง
บทช่วยสอนนี้เกี่ยวข้องกับหลายขั้นตอน ซึ่งรวมถึง (แต่ไม่จำกัดเพียง) การตรวจจับการชนกัน และแนวคิด A-Frame อื่นๆ เช่น มิกซ์อิน
- สาธิตผลิตภัณฑ์ขั้นสุดท้าย
ข้อกำหนดเบื้องต้น
เช่นเดียวกับในบทช่วยสอนก่อนหน้านี้ คุณจะต้องมีสิ่งต่อไปนี้:
- การเข้าถึงอินเทอร์เน็ต (โดยเฉพาะกับ glitch.com);
- โครงการ Glitch ที่เสร็จสิ้นจากส่วนที่ 1 (คุณสามารถดำเนินการต่อจากผลิตภัณฑ์ที่ทำเสร็จแล้วได้โดยไปที่ https://glitch.com/edit/#!/ergo-1 และคลิก “Remix to edit”;
- ชุดหูฟังเสมือนจริง (แนะนำเสริม) (ฉันใช้ Google Cardboard ซึ่งมีราคา 15 เหรียญต่อชิ้น)
ขั้นตอนที่ 1: การออกแบบอุปสรรค
ในขั้นตอนนี้ คุณออกแบบต้นไม้ที่เราจะใช้เป็นอุปสรรค จากนั้น คุณจะเพิ่มแอนิเมชั่นง่ายๆ ที่จะย้ายต้นไม้เข้าหาผู้เล่น ดังนี้:
ต้นไม้เหล่านี้จะทำหน้าที่เป็นแม่แบบสำหรับอุปสรรคที่คุณสร้างระหว่างเกม สำหรับส่วนสุดท้ายของขั้นตอนนี้ เราจะลบ "แผนผังต้นไม้" เหล่านี้
ในการเริ่มต้น ให้เพิ่ม A-Frame mixins ต่างๆ จำนวนหนึ่ง มิกซ์อินคือชุดคุณสมบัติของส่วนประกอบที่ใช้กันทั่วไป ในกรณีของเรา ต้นไม้ทั้งหมดของเราจะมีสี ความสูง ความกว้าง ความลึก ฯลฯ เหมือนกัน กล่าวอีกนัยหนึ่ง ต้นไม้ทั้งหมดของคุณจะมีลักษณะเหมือนกัน ดังนั้นจะใช้มิกซ์อินร่วมกันสองสามอย่าง
หมายเหตุ : ในบทช่วยสอนของเรา เนื้อหาเดียวของคุณจะเป็นมิกซ์อิน ไปที่หน้า A-Frame Mixins เพื่อเรียนรู้เพิ่มเติม
ในโปรแกรมแก้ไขของคุณ ให้ไปที่ index.html ทันทีหลังท้องฟ้าและก่อนแสงของคุณ เพิ่มเอนทิตี A-Frame ใหม่เพื่อถือทรัพย์สินของคุณ:
<a-sky...></a-sky> <!-- Mixins --> <a-assets> </a-assets> <!-- Lights --> ...
ในเอนทิตี a-assets
ใหม่ของคุณ ให้เริ่มต้นด้วยการเพิ่มมิกซ์อินสำหรับใบไม้ของคุณ มิกซ์อินนี้กำหนดคุณสมบัติทั่วไปสำหรับใบไม้ของต้นไม้เทมเพลต กล่าวโดยสรุป มันคือปิรามิดสีขาวแรเงาแบนสำหรับเอฟเฟกต์โพลีต่ำ
<a-assets> <a-mixin geometry=" primitive: cone; segments-height: 1; segments-radial:4; radius-bottom:0.3;" material="color:white;flat-shading: true;"></a-mixin> </a-assets>
ด้านล่างมิกซ์อินใบไม้ของคุณ ให้เพิ่มมิกซ์อินสำหรับลำต้น ลำต้นนี้จะเป็นปริซึมสี่เหลี่ยมเล็กๆ สีขาว
<a-assets> ... <a-mixin geometry=" primitive: box; height:0.5; width:0.1; depth:0.1;" material="color:white;"></a-mixin> </a-assets>
ถัดไป เพิ่มออบเจกต์ทรีเทมเพลตที่จะใช้มิกซ์อินเหล่านี้ ยังอยู่ใน index.html ให้เลื่อนลงไปที่ส่วนแพลตฟอร์ม ก่อนส่วนผู้เล่น เพิ่มส่วนต้นไม้ใหม่ โดยมีต้นไม้ว่างสามรายการ:
<a-entity ...> <!-- Trees --> <a-entity></a-entity> <a-entity></a-entity> <a-entity></a-entity> <!-- Player --> ...
ถัดไป ปรับตำแหน่ง ปรับขนาด และเพิ่มเงาให้กับเอนทิตีของต้นไม้
<!-- Trees --> <a-entity shadow scale="0.3 0.3 0.3" position="0 0.6 0"></a-entity> <a-entity shadow scale="0.3 0.3 0.3" position="0 0.6 0"></a-entity> <a-entity shadow scale="0.3 0.3 0.3" position="0 0.6 0"></a-entity>
ตอนนี้ เติมเอนทิตีของต้นไม้ด้วยลำต้นและใบไม้ โดยใช้มิกซ์อินที่เรากำหนดไว้ก่อนหน้านี้
<!-- Trees --> <a-entity ...> <a-entity mixin="foliage"></a-entity> <a-entity mixin="trunk" position="0 -0.5 0"></a-entity> </a-entity> <a-entity ...> <a-entity mixin="foliage"></a-entity> <a-entity mixin="trunk" position="0 -0.5 0"></a-entity> </a-entity> <a-entity ...> <a-entity mixin="foliage"></a-entity> <a-entity mixin="trunk" position="0 -0.5 0"></a-entity> </a-entity>
ไปที่การแสดงตัวอย่างของคุณ และตอนนี้คุณควรเห็นแผนผังแม่แบบต่อไปนี้
ตอนนี้ ทำให้ต้นไม้เคลื่อนไหวจากตำแหน่งที่ห่างไกลบนแพลตฟอร์มไปยังผู้ใช้ เช่นเคย ใช้แท็ก a-animation
:
<!-- Trees --> <a-entity ...> ... <a-animation attribute="position" ease="linear" from="0 0.6 -7" to="0 0.6 1.5" dur="5000"></a-animation> </a-entity> <a-entity ...> ... <a-animation attribute="position" ease="linear" from="-0.5 0.55 -7" to="-0.5 0.55 1.5" dur="5000"></a-animation> </a-entity> <a-entity ...> ... <a-animation attribute="position" ease="linear" from="0.5 0.55 -7" to="0.5 0.55 1.5" dur="5000"></a-animation> </a-entity>
ตรวจสอบให้แน่ใจว่ารหัสของคุณตรงกับรายการต่อไปนี้
<a-entity...> <!-- Trees --> <a-entity shadow scale="0.3 0.3 0.3" position="0 0.6 0"> <a-entity mixin="foliage"></a-entity> <a-entity mixin="trunk" position="0 -0.5 0"></a-entity> <a-animation attribute="position" ease="linear" from="0 0.6 -7" to="0 0.6 1.5" dur="5000"></a-animation> </a-entity> <a-entity shadow scale="0.3 0.3 0.3" position="-0.5 0.55 0"> <a-entity mixin="foliage"></a-entity> <a-entity mixin="trunk" position="0 -0.5 0"></a-entity> <a-animation attribute="position" ease="linear" from="-0.5 0.55 -7" to="-0.5 0.55 1.5" dur="5000"></a-animation> </a-entity> <a-entity shadow scale="0.3 0.3 0.3" position="0.5 0.55 0"> <a-entity mixin="foliage"></a-entity> <a-entity mixin="trunk" position="0 -0.5 0"></a-entity> <a-animation attribute="position" ease="linear" from="0.5 0.55 -7" to="0.5 0.55 1.5" dur="5000"></a-animation> </a-entity> <!-- Player --> ...
ไปที่หน้าตัวอย่าง แล้วคุณจะเห็นต้นไม้เคลื่อนเข้าหาคุณ
กลับไปที่โปรแกรมแก้ไขของคุณ คราวนี้ เลือก asset/ergo.js ในส่วนเกม ให้ตั้งค่าต้นไม้หลังจากโหลดหน้าต่างแล้ว
/******** * GAME * ********/ ... window.onload = function() { setupTrees(); }
ใต้ส่วนควบคุม แต่ก่อนส่วนเกม ให้เพิ่มส่วน TREES
ใหม่ ในส่วนนี้ ให้กำหนดฟังก์ชัน setupTrees
ใหม่
/************ * CONTROLS * ************/ ... /********* * TREES * *********/ function setupTrees() { } /******** * GAME * ********/ ...
ในฟังก์ชัน setupTrees
ใหม่ รับการอ้างอิงไปยังออบเจ็กต์ DOM ของแผนผังเทมเพลต และทำให้ข้อมูลอ้างอิงพร้อมใช้งานทั่วโลก
/********* * TREES * *********/ var templateTreeLeft; var templateTreeCenter; var templateTreeRight; function setupTrees() { templateTreeLeft = document.getElementById('template-tree-left'); templateTreeCenter = document.getElementById('template-tree-center'); templateTreeRight = document.getElementById('template-tree-right'); }
ถัดไป กำหนดยูทิลิตี้ removeTree
ใหม่ ด้วยยูทิลิตี้นี้ คุณสามารถลบแผนผังแม่แบบออกจากฉากได้ ภายใต้ฟังก์ชัน setupTrees
ให้กำหนดยูทิลิตี้ใหม่ของคุณ
function setupTrees() { ... } function removeTree(tree) { tree.parentNode.removeChild(tree); }
กลับไปที่ setupTrees
ใช้ยูทิลิตี้ใหม่เพื่อลบแผนผังแม่แบบ
function setupTrees() { ... removeTree(templateTreeLeft); removeTree(templateTreeRight); removeTree(templateTreeCenter); }
ตรวจสอบให้แน่ใจว่าส่วนต้นไม้และเกมของคุณตรงกับสิ่งต่อไปนี้:
/********* * TREES * *********/ var templateTreeLeft; var templateTreeCenter; var templateTreeRight; function setupTrees() { templateTreeLeft = document.getElementById('template-tree-left'); templateTreeCenter = document.getElementById('template-tree-center'); templateTreeRight = document.getElementById('template-tree-right'); removeTree(templateTreeLeft); removeTree(templateTreeRight); removeTree(templateTreeCenter); } function removeTree(tree) { tree.parentNode.removeChild(tree); } /******** * GAME * ********/ setupControls(); // TODO: AFRAME.registerComponent has to occur before window.onload? window.onload = function() { setupTrees(); }
เปิดการแสดงตัวอย่างของคุณอีกครั้ง และตอนนี้ต้นไม้ของคุณจะหายไป ตัวอย่างควรตรงกับเกมของเราเมื่อเริ่มต้นบทช่วยสอนนี้
นี่เป็นการสรุปการออกแบบแผนผังเทมเพลต
ในขั้นตอนนี้ เราครอบคลุมและใช้ A-Frame mixins ซึ่งช่วยให้เราลดความซับซ้อนของโค้ดโดยการกำหนดคุณสมบัติทั่วไป นอกจากนี้เรายังใช้ประโยชน์จากการรวม A-Frame กับ DOM เพื่อลบวัตถุออกจากฉาก A-Frame VR
ในขั้นตอนต่อไป เราจะวางไข่สิ่งกีดขวางมากมายและออกแบบอัลกอริธึมง่ายๆ เพื่อกระจายต้นไม้ไปตามเลนต่างๆ
ขั้นตอนที่ 2: อุปสรรคการวางไข่
ในเกมวิ่งที่ไม่มีที่สิ้นสุด เป้าหมายของเราคือหลีกเลี่ยงอุปสรรคที่พุ่งเข้ามาหาเรา ในการใช้งานเกมนี้โดยเฉพาะ เราใช้สามเลนตามปกติ
ไม่เหมือนกับเกมวิ่งที่ไม่มีที่สิ้นสุดส่วนใหญ่ เกม นี้รองรับเฉพาะการเคลื่อนไหวซ้ายและขวา สิ่งนี้กำหนดข้อจำกัดในอัลกอริธึมของเราในการวางไข่สิ่งกีดขวาง: เราไม่สามารถมีอุปสรรคสามอย่างในทั้งสามเลน ในเวลาเดียวกัน บินเข้าหาเรา หากเป็นเช่นนั้น ผู้เล่นจะมีโอกาสรอดเป็นศูนย์ ด้วยเหตุนี้ อัลกอริธึมการวางไข่ของเราจึงจำเป็นต้องปรับให้เข้ากับข้อจำกัดนี้
ในขั้นตอนนี้ การแก้ไขโค้ดทั้งหมดของเราจะทำใน asset/ergo.js ไฟล์ HTML จะยังคงเหมือนเดิม ไปที่ส่วน TREES
ของ asset/ergo.js
ในการเริ่มต้น เราจะเพิ่มยูทิลิตี้เพื่อวางไข่ต้นไม้ ต้นไม้ทุกต้นจะต้องมี ID เฉพาะ ซึ่งเราจะกำหนดจำนวนต้นไม้ที่มีอยู่เมื่อต้นไม้เกิด เริ่มต้นด้วยการติดตามจำนวนต้นไม้ในตัวแปรส่วนกลาง
/********* * TREES * *********/ ... var numberOfTrees = 0; function setupTrees() { ...
ต่อไป เราจะเริ่มต้นการอ้างอิงถึงองค์ประกอบ DOM ของคอนเทนเนอร์ทรี ซึ่งฟังก์ชัน spawn ของเราจะเพิ่มต้นไม้เข้าไป ยังอยู่ในส่วน TREES
ให้เพิ่มตัวแปรร่วมแล้วทำการอ้างอิง
... var treeContainer; var numberOfTrees ... function setupTrees() { ... templateTreeRight = ... treeContainer = document.getElementById('tree-container'); removeTree(...); ... }
ใช้ทั้งจำนวนต้นไม้และที่เก็บต้นไม้ เขียนฟังก์ชันใหม่ที่จะวางไข่ต้นไม้
function removeTree(tree) { ... } function addTree(el) { numberOfTrees += 1; el.id = 'tree-' + numberOfTrees; treeContainer.appendChild(el); } ...
เพื่อความสะดวกในการใช้งานในภายหลัง คุณจะต้องสร้างฟังก์ชันที่สองที่เพิ่มต้นไม้ที่ถูกต้องลงในเลนที่ถูกต้อง ในการเริ่มต้น ให้กำหนดอาร์เรย์ templates
ใหม่ในส่วน TREES
var templates; var treeContainer; ... function setupTrees() { ... templates = [templateTreeLeft, templateTreeCenter, templateTreeRight]; removeTree(...); ... }
ใช้อาร์เรย์เทมเพลตนี้ เพิ่มยูทิลิตี้ที่สร้างต้นไม้ในเลนที่กำหนด โดยให้ ID แทนซ้าย กลาง หรือขวา
function function addTree(el) { ... } function addTreeTo(position_index) { var template = templates[position_index]; addTree(template.cloneNode(true)); }
ไปที่หน้าตัวอย่างและเปิดคอนโซลนักพัฒนาซอฟต์แวร์ของคุณ ในคอนโซลนักพัฒนาซอฟต์แวร์ของคุณ ให้เรียกใช้ฟังก์ชัน addTreeTo
> addTreeTo(0); # spawns tree in left lane
ตอนนี้ คุณจะเขียนอัลกอริทึมที่วางไข่ต้นไม้แบบสุ่ม:
- เลือกเลนแบบสุ่ม (ที่ยังไม่ได้เลือกสำหรับขั้นตอนนี้);
- วางไข่ต้นไม้ด้วยความน่าจะเป็น;
- หากเกิดจำนวนต้นไม้สูงสุดในช่วงเวลานี้ ให้หยุด มิฉะนั้น ทำซ้ำขั้นตอนที่ 1
เพื่อให้เกิดผลกับอัลกอริทึมนี้ เราจะสับเปลี่ยนรายการเทมเพลตและดำเนินการทีละรายการ เริ่มต้นด้วยการกำหนดฟังก์ชันใหม่ addTreesRandomly
ที่ยอมรับอาร์กิวเมนต์ของคีย์เวิร์ดที่แตกต่างกันจำนวนหนึ่ง
function addTreeTo(position_index) { ... } /** * Add any number of trees across different lanes, randomly. **/ function addTreesRandomly( { probTreeLeft = 0.5, probTreeCenter = 0.5, probTreeRight = 0.5, maxNumberTrees = 2 } = {}) { }
ในฟังก์ชัน addTreesRandomly
ใหม่ของคุณ ให้กำหนดรายการแผนผังเทมเพลต และสับเปลี่ยนรายการ
function addTreesRandomly( ... ) { var trees = [ {probability: probTreeLeft, position_index: 0}, {probability: probTreeCenter, position_index: 1}, {probability: probTreeRight, position_index: 2}, ] shuffle(trees); }
เลื่อนลงไปที่ด้านล่างของไฟล์ และสร้างส่วนยูทิลิตี้ใหม่ พร้อมกับยูทิลิตี้ shuffle
ใหม่ ยูทิลิตีนี้จะสับเปลี่ยนอาร์เรย์ให้เข้าที่
/******** * GAME * ********/ ... /************* * UTILITIES * *************/ /** * Shuffles array in place. * @param {Array} a items An array containing the items. */ function shuffle(a) { var j, x, i; for (i = a.length - 1; i > 0; i--) { j = Math.floor(Math.random() * (i + 1)); x = a[i]; a[i] = a[j]; a[j] = x; } return a; }
กลับไปที่ฟังก์ชัน addTreesRandomly
ในส่วน Trees ของคุณ เพิ่มตัวแปรใหม่ numberOfTreesAdded
และวนซ้ำผ่านรายการต้นไม้ที่กำหนดไว้ด้านบน
function addTreesRandomly( ... ) { ... var numberOfTreesAdded = 0; trees.forEach(function (tree) { }); }
ในการวนซ้ำบนต้นไม้ วางไข่ต้นไม้ด้วยความน่าจะเป็นบางอย่างเท่านั้น และเฉพาะในกรณีที่จำนวนต้นไม้ที่เพิ่มไม่เกิน 2
. อัพเดท for loop ดังนี้
function addTreesRandomly( ... ) { ... trees.forEach(function (tree) { if (Math.random() < tree.probability && numberOfTreesAdded < maxNumberTrees) { addTreeTo(tree.position_index); numberOfTreesAdded += 1; } }); }
ในการสรุปฟังก์ชัน ให้คืนค่าจำนวนต้นไม้ที่เพิ่ม
function addTreesRandomly( ... ) { ... return numberOfTreesAdded; }
ตรวจสอบอีกครั้งว่าฟังก์ชัน addTreesRandomly
ของคุณตรงกับรายการต่อไปนี้
/** * Add any number of trees across different lanes, randomly. **/ function addTreesRandomly( { probTreeLeft = 0.5, probTreeCenter = 0.5, probTreeRight = 0.5, maxNumberTrees = 2 } = {}) { var trees = [ {probability: probTreeLeft, position_index: 0}, {probability: probTreeCenter, position_index: 1}, {probability: probTreeRight, position_index: 2}, ] shuffle(trees); var numberOfTreesAdded = 0; trees.forEach(function (tree) { if (Math.random() < tree.probability && numberOfTreesAdded < maxNumberTrees) { addTreeTo(tree.position_index); numberOfTreesAdded += 1; } }); return numberOfTreesAdded; }
สุดท้าย เมื่อต้องการวางไข่ต้นไม้โดยอัตโนมัติ ให้ตั้งเวลาที่จะเรียกใช้การวางไข่ของต้นไม้ในช่วงเวลาปกติ กำหนดตัวจับเวลาทั่วโลก และเพิ่มฟังก์ชันการฉีกขาดใหม่สำหรับตัวจับเวลานี้
/********* * TREES * *********/ ... var treeTimer; function setupTrees() { ... } function teardownTrees() { clearInterval(treeTimer); }
ถัดไป กำหนดฟังก์ชันใหม่ที่เริ่มต้นตัวจับเวลาและบันทึกตัวจับเวลาในตัวแปรส่วนกลางที่กำหนดไว้ก่อนหน้านี้ ตัวจับเวลาด้านล่างจะทำงานทุกครึ่งวินาที
function addTreesRandomlyLoop({intervalLength = 500} = {}) { treeTimer = setInterval(addTreesRandomly, intervalLength); }
สุดท้าย เริ่มจับเวลาหลังจากโหลดหน้าต่างจากส่วนเกม
/******** * GAME * ********/ ... window.onload = function() { ... addTreesRandomlyLoop(); }
ไปที่หน้าตัวอย่าง แล้วคุณจะเห็นต้นไม้วางไข่แบบสุ่ม โปรดทราบว่าไม่เคยมีต้นไม้สามต้นพร้อมกัน
นี้เป็นการสรุปขั้นตอนอุปสรรค เราได้นำแผนผังแม่แบบจำนวนหนึ่งมาสำเร็จและสร้างอุปสรรคจำนวนนับไม่ถ้วนจากแม่แบบ อัลกอริธึมการวางไข่ของเรายังเคารพข้อจำกัดตามธรรมชาติในเกมเพื่อให้เล่นได้
ในขั้นตอนต่อไป มาเพิ่มการทดสอบการชนกัน
ขั้นตอนที่ 3: การทดสอบการชน
ในส่วนนี้ เราจะทำการทดสอบการชนกันระหว่างสิ่งกีดขวางกับผู้เล่น การทดสอบการชนนี้ง่ายกว่าการทดสอบการชนในเกมอื่นๆ ส่วนใหญ่ อย่างไรก็ตาม ผู้เล่นจะเคลื่อนที่ไปตามแกน x เท่านั้น ดังนั้นเมื่อใดก็ตามที่ต้นไม้ข้ามแกน x ให้ตรวจสอบว่าเลนของต้นไม้นั้นเหมือนกับเลนของผู้เล่นหรือไม่ เราจะใช้การตรวจสอบง่ายๆ สำหรับเกมนี้
ไปที่ index.html ลงไปที่ส่วน TREES
เราจะเพิ่มข้อมูลเลนให้กับต้นไม้แต่ละต้น สำหรับแต่ละต้นไม้ เพิ่ม data-tree-position-index=
ดังต่อไปนี้ เพิ่ม class="tree"
เพื่อให้เราสามารถเลือกต้นไม้ทั้งหมดได้อย่างง่ายดาย:
<a-entity data-tree-position-index="1" class="tree" ...> </a-entity> <a-entity data-tree-position-index="0" class="tree" ...> </a-entity> <a-entity data-tree-position-index="2" class="tree" ...> </a-entity>
ไปที่ asset/ergo.js และเรียกใช้ฟังก์ชัน setupCollisions
ใหม่ในส่วน GAME
นอกจากนี้ ให้กำหนดตัวแปรสากล isGameRunning
ใหม่ที่ระบุว่าเกมที่มีอยู่กำลังทำงานอยู่แล้วหรือไม่
/******** * GAME * ********/ var isGameRunning = false; setupControls(); setupCollision(); window.onload = function() { ...
กำหนดส่วนการ TREES
COLLISIONS
ก่อนส่วนเกม ในส่วนนี้ ให้กำหนดฟังก์ชัน setupCollisions
/********* * TREES * *********/ ... /************** * COLLISIONS * **************/ const POSITION_Z_OUT_OF_SIGHT = 1; const POSITION_Z_LINE_START = 0.6; const POSITION_Z_LINE_END = 0.7; function setupCollision() { } /******** * GAME * ********/
เช่นเคย เราจะลงทะเบียนคอมโพเนนต์ AFRAME และใช้ตัวฟังเหตุการณ์ tick
เพื่อเรียกใช้โค้ดในทุกขั้นตอน ในกรณีนี้ เราจะลงทะเบียนส่วนประกอบกับ player
และทำการตรวจสอบกับต้นไม้ทั้งหมดใน Listener นั้น:
function setupCollisions() { AFRAME.registerComponent('player', { tick: function() { document.querySelectorAll('.tree').forEach(function(tree) { } } } }
ใน for
loop ให้เริ่มต้นด้วยการรับข้อมูลที่เกี่ยวข้องของ tree:
document.querySelectorAll('.tree').forEach(function(tree) { position = tree.getAttribute('position'); tree_position_index = tree.getAttribute('data-tree-position-index'); tree_id = tree.getAttribute('id'); }
ถัดไป ยังอยู่ในลูป for
ให้เอาต้นไม้ออกหากมองไม่เห็น ทันทีหลังจากดึงคุณสมบัติของต้นไม้ออก:
document.querySelectorAll('.tree').forEach(function(tree) { ... if (position.z > POSITION_Z_OUT_OF_SIGHT) { removeTree(tree); } }
ต่อไป หากไม่มีเกมที่กำลังรันอยู่ อย่าตรวจสอบว่ามีการชนกันหรือไม่
document.querySelectorAll('.tree').forEach(function(tree) { if (!isGameRunning) return; }
สุดท้าย (ยังอยู่ใน for
loop) ให้ตรวจสอบว่าต้นไม้มีตำแหน่งเดียวกันกับผู้เล่นหรือไม่ ถ้าใช่ ให้เรียกใช้ฟังก์ชัน gameOver
ที่ยังไม่ได้กำหนด:
document.querySelectorAll('.tree').forEach(function(tree) { ... if (POSITION_Z_LINE_START < position.z && position.z < POSITION_Z_LINE_END && tree_position_index == player_position_index) { gameOver(); } }
ตรวจสอบว่าฟังก์ชัน setupCollisions
ของคุณตรงกับรายการต่อไปนี้:
function setupCollisions() { AFRAME.registerComponent('player', { tick: function() { document.querySelectorAll('.tree').forEach(function(tree) { position = tree.getAttribute('position'); tree_position_index = tree.getAttribute('data-tree-position-index'); tree_id = tree.getAttribute('id'); if (position.z > POSITION_Z_OUT_OF_SIGHT) { removeTree(tree); } if (!isGameRunning) return; if (POSITION_Z_LINE_START < position.z && position.z < POSITION_Z_LINE_END && tree_position_index == player_position_index) { gameOver(); } }) } }) }
นี่เป็นการสรุปการตั้งค่าการชนกัน ตอนนี้ เราจะเพิ่มสิ่งที่ดีสองสามอย่างเพื่อแยกลำดับ startGame
และ gameOver
ไปที่ส่วน GAME
อัปเดตบล็อก window.onload
ให้ตรงกับรายการต่อไปนี้ โดยแทนที่ addTreesRandomlyLoop
ด้วยฟังก์ชัน startGame
ที่ยังไม่ได้กำหนด
window.onload = function() { setupTrees(); startGame(); }
ภายใต้การเรียกใช้ฟังก์ชันการตั้งค่า ให้สร้างฟังก์ชัน startGame
ใหม่ ฟังก์ชันนี้จะเริ่มต้นตัวแปร isGameRunning
ตามลำดับ และป้องกันการเรียกซ้ำซ้อน
window.onload = function() { ... } function startGame() { if (isGameRunning) return; isGameRunning = true; addTreesRandomlyLoop(); }
สุดท้าย ให้นิยาม gameOver
ซึ่งจะแจ้งเตือนว่า “Game Over!” ข้อความสำหรับตอนนี้
function startGame() { ... } function gameOver() { isGameRunning = false; alert('Game Over!'); teardownTrees(); }
นี่เป็นการสรุปส่วนการทดสอบการชนกันของเกมวิ่งไม่รู้จบ
ในขั้นตอนนี้ เราใช้ส่วนประกอบ A-Frame อีกครั้งและยูทิลิตี้อื่นๆ จำนวนหนึ่งที่เราเพิ่มไว้ก่อนหน้านี้ เรายังได้จัดระเบียบใหม่และแยกฟังก์ชั่นเกมออกมาอย่างเหมาะสม จากนั้นเราจะเพิ่มฟังก์ชันของเกมเหล่านี้เพื่อให้ได้รับประสบการณ์เกมที่สมบูรณ์ยิ่งขึ้น
บทสรุป
ในตอนที่ 1 เราได้เพิ่มส่วนควบคุมที่เหมาะกับชุดหูฟัง VR: มองไปทางซ้ายเพื่อเลื่อนไปทางซ้าย และทางขวาเพื่อเลื่อนไปทางขวา ในส่วนที่สองของซีรีส์นี้ ฉันได้แสดงให้คุณเห็นว่าการสร้างเกมเสมือนจริงขั้นพื้นฐานที่ใช้งานได้จริงนั้นทำได้ง่ายเพียงใด เราได้เพิ่มตรรกะของเกมเพื่อให้นักวิ่งที่ไม่มีที่สิ้นสุดตรงกับความคาดหวังของคุณ: วิ่งตลอดไปและมีอุปสรรคอันตรายมากมายที่บินไปที่ผู้เล่น จนถึงตอนนี้ คุณได้สร้างเกมที่ใช้งานได้พร้อมการรองรับชุดหูฟังเสมือนจริงแบบไม่ต้องใช้คีย์บอร์ด
ต่อไปนี้เป็นแหล่งข้อมูลเพิ่มเติมสำหรับการควบคุม VR และชุดหูฟังต่างๆ:
- A-Frame สำหรับชุดหูฟัง VR
แบบสำรวจเบราว์เซอร์และชุดหูฟังที่ A-Frame VR รองรับ - A-Frame สำหรับตัวควบคุม VR
วิธีที่ A-Frame ไม่รองรับคอนโทรลเลอร์, คอนโทรลเลอร์ 3DoF และคอนโทรลเลอร์ 6DoF นอกเหนือจากทางเลือกอื่นสำหรับการโต้ตอบ
ในส่วนถัดไป เราจะเพิ่มรายละเอียดเล็กน้อยและซิงโครไนซ์ สถานะของเกม ซึ่งจะทำให้เราเข้าใกล้เกมที่มีผู้เล่นหลายคนมากขึ้นอีกก้าว