ฉันเพิ่งได้สัมผัสกับ Canvas มานานกว่าหนึ่งเดือน นี่เป็นครั้งแรกที่นำกระบวนการเกมไปใช้อย่างสมบูรณ์ และการเก็บเกี่ยวก็ค่อนข้างใหญ่
ภาพหน้าจอของเกมยิงปืน
ไปที่เดโมก่อน: https://littleyljy.github.io/demo/shootgame/
กฎของเกมผู้เล่นจะต้องควบคุมเครื่องบินเพื่อยิงกระสุนและทำลายสัตว์ประหลาดที่กำลังเคลื่อนที่ หากมอนสเตอร์ทั้งหมดถูกทำลาย เกมจะสำเร็จ หากมอนสเตอร์เคลื่อนตัวไปด้านล่างสุด เกมจะล้มเหลว
เกมนี้แบ่งออกเป็นหลายฉาก:
เพื่อให้สลับฉากได้ คุณต้องแสดงก่อน: ไม่มีสำหรับทุกฉาก จากนั้นควบคุมสถานะข้อมูลผ่าน js เพื่อเริ่ม เล่น ล้มเหลว สำเร็จ สำเร็จทั้งหมด และหยุดเพื่อใช้การแสดงฉากที่เกี่ยวข้อง: บล็อก
HTML และ CSS มีดังนี้:
<div id=game data-status=start> <div class=game-panel> <section class=game-intro game-ui> <h1 class=section-title>เกมยิงปืน</h1> <p class=game- คำอธิบาย>นี่คือเกมยิงปืนที่น่าติดตาม ใช้ ← และ → เพื่อควบคุมเครื่องบินของคุณ ใช้พื้นที่ในการยิง และใช้ Enter เพื่อหยุดเกมชั่วคราว มาทำลายสัตว์ประหลาดอวกาศด้วยกัน! </p> <p class=game-level>ระดับปัจจุบัน: 1</p> <button class=js-play button>เริ่มเกม</button> </section> <section class=game-failed game-ui> <h1 class=section-title>จบเกม</h1> <p class=game-info-text>คะแนนสุดท้าย: <span class=score></span></p> <button class=js-replay button> เริ่มต้นใหม่อีกครั้ง</ปุ่ม> </section> <section class=game-success game-ui> <h1 class=section-title>ความสำเร็จของเกม</h1> <p class=game-next-level game-info-text></p> <button class=js-next button>เล่นเกมต่อ</button> </section> <section class=game-all-success game-ui> <h1 class=section-title>ผ่านสำเร็จแล้ว</h1> <p class=game- ระดับถัดไป game-info-text>คุณได้ป้องกันการโจมตีของมอนสเตอร์ทั้งหมดได้สำเร็จ </p> <ปุ่ม class=js-replay ปุ่ม>เล่นอีกครั้ง</ปุ่ม> </section> <section class=game-stop game-ui> <h1 class=section-title>เกมหยุดชั่วคราว</h1> < ปุ่ม class=js-stop button>เกมดำเนินต่อไป</button> </section> </div> <div class=game-info game-ui> <span class=title>คะแนน:</span> <span class=score > </span> </div> <canvas id=canvas width=700 height=600> <!-- กระดานวาดภาพแอนิเมชัน --> </canvas> </div>
#game{ ความกว้าง: 700px; ความสูง: 600px; ตำแหน่ง: ญาติ; ซ้าย: 50%; ระยะขอบ: 0 0 0 -350px; );}.game-ui{ จอแสดงผล: ไม่มีช่องว่างภายใน: 55px; เส้นขอบกล่อง ความสูง: 100%; [data-status=start] .game-intro { display: block; padding-top: 180px; ขนาดพื้นหลัง: 200px; [data-status=playing] .game-info { แสดง: บล็อก; ตำแหน่ง: สัมบูรณ์; ซ้าย: 0; การขยาย: 20px; ข้อมูลสถานะ = หยุด] .game-stop { display: block; padding-top: 180px; url(./img/bg-end.png) ไม่ซ้ำ 380px 190px;เชิงวัตถุ
ทั้งเกมสามารถปฏิบัติต่อสัตว์ประหลาด (ศัตรู) เครื่องบิน (เครื่องบิน) และกระสุน (กระสุน) เป็นวัตถุ เช่นเดียวกับวัตถุการกำหนดค่า (CONFIG) และวัตถุในเกม (GAME) ที่ควบคุมตรรกะของเกม
การกำหนดค่าที่เกี่ยวข้องกับเกม/** * การกำหนดค่าที่เกี่ยวข้องกับเกม* @type {Object} */var CONFIG = { status: 'start', // เกมเริ่มต้นตามค่าเริ่มต้นเป็นระดับเริ่มต้น: 1, // ระดับเริ่มต้นของเกมทั้งหมดระดับ: 6, // ปิดทั้งหมด 6 รายการ numPerLine: 7, // จำนวนมอนสเตอร์เริ่มต้นของเกมต่อบรรทัด canvasPadding: 30, // ช่วงผ้าใบเริ่มต้น bulletSize: 10, // ความยาวกระสุนเริ่มต้น bulletSpeed: 10, // ความเร็วการเคลื่อนที่ของกระสุนเริ่มต้น ศัตรูความเร็ว: 2, // ระยะการเคลื่อนที่ของศัตรูเริ่มต้น ศัตรูขนาด: 50, // ขนาดศัตรูเริ่มต้น ศัตรูช่องว่าง: 10, // ระยะห่างเริ่มต้นระหว่างศัตรู ศัตรูไอคอน: './img/enemy.png', / / รูปภาพของ ศัตรูสัตว์ประหลาดBoomIcon: './img/boom.png', // รูปภาพของศัตรูแห่งความตายของสัตว์ประหลาดทิศทาง: 'right', // ศัตรูเริ่มต้นเคลื่อนที่ไปทางขวาที่ระนาบเริ่มต้น ความเร็ว: 5, // ระยะทางเริ่มต้นที่เครื่องบินเคลื่อนที่ในแต่ละขั้นตอน ขนาดเครื่องบิน: { ความกว้าง: 60, ความสูง: 100 }, // ขนาดเริ่มต้นของเครื่องบิน, ไอคอนเครื่องบิน: '. /img/plane.png' };กำหนดคลาสผู้ปกครอง
เนื่องจากสัตว์ประหลาด (ศัตรู) เครื่องบิน (เครื่องบิน) และกระสุน (กระสุน) ล้วนมีแอตทริบิวต์ x, y, ขนาด, ความเร็ว และเมธอด move() เหมือนกัน คุณจึงสามารถกำหนดองค์ประกอบคลาสพาเรนต์และนำไปใช้โดยสืบทอดคลาสพาเรนต์จาก คลาสย่อย
/*คลาสพาเรนต์: ประกอบด้วย xy speed move() Draw()*/var Element = function (opts) { this.opts = opts || {}; // กำหนดพิกัด, ขนาด, ความเร็ว this.x = opts.x; this.y = opts.y; this.size = opts.size; this.speed = opts.speed;}; Element.prototype.move = ฟังก์ชัน (x, y) { var addX = x || 0; addY = y ||.0; this.x += addX; this.y += addY;};//ฟังก์ชันที่สืบทอดฟังก์ชันต้นแบบ inheritPrototype(subType, superType) { var proto = Object.create(superType.prototype); โปรโต .constructor = ประเภทย่อย; subType.prototype = โปรโต;}
เมธอด move(x, y) จะเรียงซ้อนตามค่า (x, y) ที่ส่งเข้ามา
กำหนดสัตว์ประหลาดมอนสเตอร์มีคุณสมบัติพิเศษ: สถานะของมอนสเตอร์, รูปภาพ, boomCount ที่ควบคุมระยะเวลาของสถานะการระเบิด และวิธีการวาด (), ลง (), ทิศทาง () และบูม ()
/*Enemy*/var Enemy = function (opts) { this.opts = opts ||. {}; // เรียกแอตทริบิวต์คลาสหลัก Element.call (นี่, opts); // สถานะแอตทริบิวต์พิเศษและรูปภาพ this.status = ' ปกติ';//ปกติ เฟื่องฟู noomed this.enemyIcon = opts.enemyIcon; this.enemyBoomIcon = opts.enemyBoomIcon = 0;};//สืบทอดวิธีองค์ประกอบ inheritPrototype(ศัตรู, องค์ประกอบ);//วิธีการ: วาดศัตรู Enemy.prototype.draw = function () { if (this.enemyIcon && this.enemyBoomIcon) { switch (this.status ) { case 'normal': var ศัตรู Icon = รูปภาพใหม่ (); ศัตรู Icon.src = this.enemyIcon; ctx.drawImage (enemyIcon, this.x, this.y, this.size, this.size); ตัวพิมพ์ใหญ่ 'เฟื่องฟู': var ศัตรูBoomIcon = รูปภาพใหม่ (); this.y, this.size, this.size); ตัวพิมพ์ 'บูม': ctx.clearRect(this.x, this.y, this.size, this.size); ค่าเริ่มต้น: break; } } คืนสิ่งนี้;};//Method: down Move down Enemy.prototype.down = function () { this.move(0, this.size); ;//วิธีการ: เลื่อนไปทางซ้ายหรือขวา Enemy.prototype.direction = function (ทิศทาง) { if (direction === 'right') { this.move(this.speed, 0 } else {); this.move(-this.speed, 0); } คืนสิ่งนี้;};//วิธีการ: ศัตรูระเบิด Enemy.prototype.booming = function () { this.status = 'boomCount'; (this.boomCount > 4) { this.status = 'boomed'; } คืนสิ่งนี้;}
สัญลักษณ์แสดงหัวข้อย่อยมีวิธี fly() และ Draw()
/*Bullet*/var Bullet = function (opts) { this.opts = opts ||. {}; Element.call(this, opts);};inheritPrototype(Bullet, Element);//วิธีการ: ปล่อยให้กระสุนบิน . Prototype.fly = function () { this.move(0, -this.speed); return this;};//วิธีการ: วาดสัญลักษณ์แสดงหัวข้อย่อย Bullet.prototype.draw = function () { ctx.beginPath(); ctx. strokeStyle = '#fff'; ctx.moveTo(this.x, this.y); ctx.lineTo(this.x, this.y - CONFIG.bulletSize() ; ctx. stroke(); คืนสิ่งนี้;};
วัตถุเครื่องบินประกอบด้วยคุณลักษณะเฉพาะ: สถานะ ความกว้างและความสูง รูปภาพ ค่า Abscissa สูงสุดและต่ำสุด และวิธีการ haveHit(), วาด(), ทิศทาง(), ยิง() และ DrawBullets()
/*Plane*/var Plane = function (opts) { this.opts = opts ||. {}; = opts.width; this.height = this.planeIcon = opts.planeIcon; this.minX = opts.minX; this.maxX; //สัญลักษณ์แสดงหัวข้อย่อยที่เกี่ยวข้อง this.bulletSize = []; this.bulletSpeed = opts.bulletSpeed ||. CONFIG.bulletSize = opts.bulletSize ||. CONFIG.bulletSize;}; (เครื่องบิน องค์ประกอบ) ;//วิธีการ: กระสุนกระทบเป้าหมาย Plane.prototype.hasHit = function (ศัตรู) { var bullets = this.bullets; for (var i = bullets.length - 1; i >= 0; i--) { var bullet = bullets[i]; var isHitPosX = (enemy.x < bullet.x) && (bullet.x < (enemy.x + ศัตรู.ขนาด)); var isHitPosY = (ศัตรู.y < bullet.y) && (bullet.y < (ศัตรู.y + ศัตรู.ขนาด)); (isHitPosX && isHitPosY) { this.bullets.splice(i, 1); return true; } } return false;};//วิธีการ: วาดระนาบ Plane.prototype.draw = function () { this.drawBullets(); varplaneIcon = รูปภาพใหม่ ();planeIcon.src = this.planeIcon; ctx.drawImage (planeIcon, this.x, this.y, this.width, this.height); กลับสิ่งนี้;}; // วิธีการ: ทิศทางเครื่องบิน Plane.prototype.direction = ฟังก์ชั่น (ทิศทาง) { var speed = this.speed; ) { เครื่องบินความเร็ว = this.x < this.minX ? 0 : -ความเร็ว; } อื่น ๆ { เครื่องบินความเร็ว = this.x > this.maxX ? 0 : ความเร็ว; console.log('planeSpeed:', planSpeed); console.log('this.x:', this.x); console.log('this.minX:', this.minX); .maxX:', this.maxX); this.move (planeSpeed, 0); คืนสิ่งนี้; // การเรียกลูกโซ่ที่สะดวก}; // วิธีการ: เปิดตัวสัญลักษณ์แสดงหัวข้อย่อย Plane.prototype.shoot = function () { var bulletPosX = this.x + this.width / 2; this.bullets.push (กระสุนใหม่ ({ x: bulletPosX, y: this.y, ขนาด: this.bulletSize, ความเร็ว: this.bulletSpeed })); นี้; };//วิธีการ: วาดสัญลักษณ์แสดงหัวข้อย่อย Plane.prototype.drawBullets = function () { var bullets = this.bullets; var i = bullets.length; (i--) { var bullet = bullets[i]; if (bullet.y <= 0) { bullets.splice(i, 1);
เหตุการณ์ของแป้นพิมพ์มีสถานะดังต่อไปนี้:
เนื่องจากเครื่องบินจำเป็นต้องเคลื่อนที่ต่อไปเมื่อกดปุ่มซ้าย (keyCode=37) และปุ่มขวา (keyCode=39) (keydown) และคีย์อัพจะไม่เคลื่อนที่เมื่อปล่อย เมื่อกดช่องว่าง (keyCode=32) หรือแป้นลูกศรขึ้น (keyCode=38) (keydown) กระสุนจะถูกยิง และเมื่อปล่อย keyup จะหยุดยิง กดปุ่ม Enter (keyCode=13) เพื่อหยุดเกมชั่วคราว ดังนั้น คุณจะต้องกำหนดอ็อบเจ็กต์ KeyBoard เพื่อตรวจสอบว่า onkeydown และ onkeyup กำลังกดหรือปล่อยคีย์หรือไม่
เนื่องจากปุ่มซ้ายและขวาขัดแย้งกัน เพื่อความปลอดภัย คุณต้องตั้งค่าปุ่มขวาเป็นเท็จเมื่อกดปุ่มซ้าย เช่นเดียวกับการคลิกขวา
// เหตุการณ์คีย์บอร์ด var KeyBoard = function () { document.onkeydown = this.keydown.bind (this); document.onkeyup = this.keyup.bind (this);}; // วัตถุคีย์บอร์ด KeyBoard.prototype = { pressedLeft: เท็จ, pressedRight: เท็จ, pressedUp: เท็จ, มือถือซ้าย: เท็จ, จัดขึ้นขวา: เท็จ, pressedSpace: เท็จ, pressedEnter: เท็จ, keydown: ฟังก์ชั่น (e) { คีย์ var = e.keyCode; switch (คีย์) { กรณีที่ 32://Space - กระสุนไฟ this.pressedSpace = true; false; this.heldRight = false; กรณีที่ 38: // ปุ่มลูกศรขึ้น - เปิดสัญลักษณ์แสดงหัวข้อย่อย this.pressedUp = true; = false; this.pressedRight = true; this.heldRight = true; break; case 13://Enter key - หยุดเกมชั่วคราว this.pressedEnter = true; .keyCode; switch (คีย์) { กรณีที่ 32: this.pressedSpace = false; กรณีที่ 37: this.heldLeft = false; this.pressedUp = false; กรณีที่ 39: this.heldRight = false; this.pressedRight = false; กรณีที่ 13: this.pressedEnter = false;ตรรกะของเกม
วัตถุเกม (GAME) มีตรรกะของทั้งเกม รวมถึง init (การเริ่มต้น), bindEvent (ปุ่มเชื่อมโยง), setStatus (การอัปเดตสถานะเกม), เล่น (ในเกม), หยุด (หยุดชั่วคราว), สิ้นสุด (สิ้นสุด) ฯลฯ ., ในสิ่งนี้ไม่ได้ขยายคำอธิบาย นอกจากนี้ยังมีฟังก์ชันต่างๆ เช่น การสร้างสัตว์ประหลาดและองค์ประกอบของเกมวาดภาพ
//วัตถุเกมทั้งหมด var GAME = { //ชุดของฟังก์ชันเชิงตรรกะ // ฟังก์ชันองค์ประกอบของเกม}1. การเริ่มต้น
ฟังก์ชันการเริ่มต้นส่วนใหญ่จะกำหนดพิกัดเริ่มต้นของเครื่องบิน ระยะการเคลื่อนที่ของเครื่องบิน ระยะการเคลื่อนที่ของสัตว์ประหลาด เริ่มต้นคะแนน อาร์เรย์ของสัตว์ประหลาด สร้างวัตถุคีย์บอร์ด และดำเนินการเพียงครั้งเดียว
/** * ฟังก์ชันการเริ่มต้น ฟังก์ชันนี้จะดำเนินการเพียงครั้งเดียว * @param {object} opts * @return {[type]} [description] */init: function (opts) { //Set opts var opts = Object.assign ( {}, opts, CONFIG); // รวมพารามิเตอร์ทั้งหมด this.opts = opts; this.status = 'start'; // คำนวณพิกัดเริ่มต้นของวัตถุเครื่องบิน this.planePosX = canvasWidth / 2 - opts.planeSize.width; this.planePosY = canvasHeight - opts.planeSize.height - opts.canvasPadding; // พิกัดระนาบจำกัด this.planeMinX = opts.canvasPadding; width; // คำนวณพื้นที่การเคลื่อนไหวของศัตรู this.enemyMinX = opts.canvasPadding; this.enemyMaxX = canvasWidth - opts.canvasPadding - opts.enemySize; //คะแนนถูกตั้งค่าเป็น 0 this.score = 0; this.keyBoard = new KeyBoard(); this.bindEvent(); } );2. เหตุการณ์ปุ่มผูก
เนื่องจากฉากในเกมหลายฉากมีปุ่มสำหรับเริ่มเกม (playBtn) รีสตาร์ท (replayBtn) ระดับถัดไปของเกม (nextBtn) และหยุดเกมชั่วคราวเพื่อดำเนินการต่อ (stopBtn) เราจำเป็นต้องดำเนินกิจกรรมที่แตกต่างกันสำหรับปุ่มที่แตกต่างกัน
เหตุผลในการกำหนด var self = this; ในฟังก์ชัน bindEvent สิ่งนี้ชี้ไปที่วัตถุ GAME และใน playBtn.onclick = function () {}; นี่ชี้ไปที่ playBtn เห็นได้ชัดว่าไม่ใช่สิ่งที่เราต้องการ เนื่องจาก playBtn ไม่มีเหตุการณ์ play() มีเพียง วัตถุ GAME มี ดังนั้น จำเป็นต้องกำหนดออบเจ็กต์ GAME ให้กับตัวแปรเอง จากนั้นจึงสามารถเรียกใช้เหตุการณ์ play() ใน playBtn.onclick = function () {};
ควรสังเกตว่าปุ่ม replayBtn ปรากฏขึ้นทั้งในสถานการณ์ที่ล้มเหลวและการกวาดล้าง ดังนั้นสิ่งที่ได้รับคือชุดของ .js-replay ทั้งหมด จากนั้น forEach จะวนซ้ำผ่านแต่ละปุ่ม replayBtn รีเซ็ตระดับและคะแนน และเรียกเหตุการณ์ play()
bindEvent: function () { var self = this; var playBtn = document.querySelector('.js-play'); var replayBtn = document.querySelectorAll('.js-replay'); var nextBtn = document.querySelector('. js-next'); var stopBtn = document.querySelector('.js-stop'); // เริ่มการเชื่อมโยงปุ่มเกม playBtn.onclick = function () { self.play(); }; // รีสตาร์ทปุ่มเกม replayBtn.forEach(function (e) { e.onclick = function () { self.opts.level = 1 ; self.play(); self.score = 0; TotalScoreText.innerText = self.score; ปุ่มเกมระดับถัดไปผูก nextBtn.onclick = ฟังก์ชั่น () { self.play(); }; ('กำลังเล่น'); self.updateElement( };3.สร้างเครื่องบิน
createPlane: function () { var opts = this.opts; this.plane = เครื่องบินใหม่ ({ x: this.planePosX, y: this.planePosY, ความกว้าง: opts.planeSize.width, ความสูง: opts.planeSize.height, minX : this.planeMinX, ความเร็ว: opts.planeSpeed, maxX: this.planeMaxX, planIcon: opts.planeIcon });}4. สร้างกลุ่มมอนสเตอร์
เนื่องจากมอนสเตอร์ปรากฏเป็นกลุ่ม และจำนวนมอนสเตอร์ในแต่ละเลเวลก็แตกต่างกันเช่นกัน หน้าที่ของ for loops สองตัวคือการสร้างแถวของมอนสเตอร์ และเพิ่มแถวเลเวลของมอนสเตอร์ตามจำนวนเลเวล หรือเพิ่มความเร็วของมอนสเตอร์ (ความเร็ว: ความเร็ว + i,) เพื่อเพิ่มความยากของแต่ละระดับ เป็นต้น
//สร้างศัตรู createEnemy: function (enemyType) { var opts = this.opts; var level = opts.level; var numPerLine = opts.numPerLine; .enemyGap; var size = opts.enemySize; var speed = opts.enemySpeed; //เพิ่มบรรทัดไปที่ศัตรูสำหรับแต่ละระดับที่คุณอัพเกรด (var i = 0; i < ระดับ; i++) { สำหรับ (var j = 0; j < numPerLine; j++) { //พารามิเตอร์สำหรับองค์ประกอบที่ครอบคลุม var initOpt = { x: ช่องว่างภายใน + j * (ขนาด + ช่องว่าง), y: ช่องว่างภายใน + i * (ขนาด + ช่องว่าง), ขนาด: ขนาด, ความเร็ว: ความเร็ว, สถานะ: ประเภทศัตรู, ศัตรูไอคอน: opts.enemyIcon, ศัตรูBoomIcon: opts.enemyBoomIcon };5. อัพเดทมอนสเตอร์
รับค่า x ของอาร์เรย์สัตว์ประหลาดและพิจารณาว่ามันถึงขอบของผืนผ้าใบหรือไม่ ถ้ามันถึงขอบ สัตว์ประหลาดจะเคลื่อนลงด้านล่าง ในขณะเดียวกันก็ต้องติดตามสถานะของมอนสเตอร์ด้วย ไม่ว่ามอนสเตอร์ในสถานะปกติจะถูกโจมตี มอนสเตอร์ที่อยู่ในสถานะระเบิด และมอนสเตอร์ที่หายไปจะต้องถูกลบออกจากอาร์เรย์และทำคะแนนไปพร้อมๆ กัน
// อัปเดตสถานะศัตรู updateEnemeis: { var opts = this.opts; varplane = this.plane; var ศัตรู = this.enemies; var i = ศัตรู.ความยาว = false;// var ศัตรู X = getHorizontalBoundary (ศัตรู); ถ้า (ศัตรู X.minX < this.enemyMinX || ศัตรู X.maxX >= this.enemyMaxX) { console.log('enemiesX.minX', ศัตรู X.minX); console.log ('enemiesX.maxX', ศัตรู X.maxX); opts.enemyDirection === 'right' ? '; console.log('opts.enemyDirection', opts.enemyDirection); isFall = true; } //วนซ้ำศัตรูในขณะที่ (i--) { var ศัตรู = ศัตรู [i]; if (isFall) { ศัตรู.ลง (); } ศัตรู (opts.enemyDirection); สลับ (enemy.status) { กรณี 'ปกติ': ถ้า (plane.hasHit (ศัตรู)) { ศัตรู .booming(); } กรณี 'เฟื่องฟู': ทำลาย; ค่าเริ่มต้น: แบ่ง; } } },
ฟังก์ชันของฟังก์ชัน getHorizontalBoundary คือการสำรวจค่า x ของแต่ละองค์ประกอบของอาร์เรย์ กรองค่าที่มากกว่าหรือน้อยกว่าออก และรับค่า x สูงสุดและต่ำสุดของอาร์เรย์
// รับฟังก์ชันขอบเขตแนวนอนของอาร์เรย์ getHorizontalBoundary(array) { var min, max; array.forEach(function (item) { if (!min && !max) { min = item.x; max = item.x; } else { if (item.x < min) { min = item.x; } if (item.x > max) { max = item.x; } }); สูงสุด }}6. อัพเดตแผงแป้นพิมพ์
กดปุ่ม Enter เพื่อดำเนินการฟังก์ชัน stop() กดปุ่มซ้ายเพื่อเลื่อนเครื่องบินไปทางซ้าย กดปุ่มขวาเพื่อเลื่อนเครื่องบินไปทางขวา และกดปุ่ม Space เพื่อดำเนินการยิงกระสุนเครื่องบินเพื่อป้องกันกระสุน จากการเชื่อมต่อเป็นเส้นตรง ให้ตั้งค่า keyBoard ที่นี่ และ keyBoard.pressedSpace เป็นเท็จ
updatePanel: function () { var เครื่องบิน = this.plane; var keyBoard = this.keyBoard; if (keyBoard.pressedEnter) { this.stop(); return; ทิศทาง ('ซ้าย'); } ถ้า (keyBoard.pressedRight || keyBoard.heldRight) { เครื่องบิน.ทิศทาง ('ขวา'); (keyBoard.pressedUp || keyBoard.pressedSpace) { keyBoard.pressedUp = false; keyBoard.pressedSpace = false; เครื่องบิน.ยิง();7. วาดองค์ประกอบทั้งหมด
วาด: function () { this.renderScore(); this.plane.draw(); this.enemies.forEach(function (enemy) { //console.log('draw:this.enemy',enemy); ศัตรู. วาด(); }); },8. อัปเดตองค์ประกอบทั้งหมด
ขั้นแรก ให้พิจารณาว่าความยาวของอาร์เรย์มอนสเตอร์เป็น 0 หรือไม่ หากเป็น 0 และระดับเท่ากับระดับทั้งหมด แสดงว่าผ่านระดับนั้นแล้ว มิฉะนั้น หน้าจอการเตรียมเกมสำหรับระดับถัดไปจะปรากฏขึ้น หากพิกัด y ของอาร์เรย์มอนสเตอร์มากกว่าพิกัด y ของเครื่องบินบวกกับความสูงของมอนสเตอร์ เกมจะล้มเหลว
หลักการของแอนิเมชั่นแคนวาสคือการวาด อัปเดต และล้างแคนวาสอย่างต่อเนื่อง
หลักการของการหยุดเกมชั่วคราวคือการป้องกันไม่ให้ฟังก์ชัน requestAnimationFrame() ทำงาน แต่ไม่ต้องรีเซ็ตองค์ประกอบ ดังนั้นเมื่อสถานะของสถานะถูกตัดสินให้หยุด ฟังก์ชันจะถูกกระโดดออก
// อัปเดตสถานะขององค์ประกอบทั้งหมด updateElement: function () { var self = this; var opts = this.opts; var ศัตรู = this.enemies; if (enemies.length === 0) { if (opts.level = == opts.totalLevel) { this.end('all-success'); } else { this.end('success'); } ถ้า (ศัตรู [enemies.length - 1].y >= this.planePosY - opts.enemySize) { this.end('failed'); //ล้างแคนวาส ctx.clearRect(0, 0, canvasWidth, canvasHeight); canvas this .draw(); // อัพเดตสถานะองค์ประกอบ this.updatePanel (); this.updateEnemeis (); // วนซ้ำ updateElement requestAnimationFrame (ฟังก์ชั่น) if(self.status === 'หยุด'){ return; }else{ self.updateElement();เขียนในตอนท้าย
ด้วยขั้นตอนข้างต้น ฟังก์ชั่นพื้นฐานของเกมจะเสร็จสมบูรณ์ การควบคุมกระบวนการเกมอื่นๆ รวมถึงการเริ่มต้น การสิ้นสุด การคำนวณคะแนน ฯลฯ จะไม่มีการอธิบายไว้ที่นี่
สิ่งที่สามารถปรับให้เหมาะสมได้: เมื่อกดสเปซบาร์ค้างไว้ กระสุนจะยิงได้อย่างต่อเนื่อง อย่างไรก็ตาม เมื่อฉันกดปุ่มทิศทางอีกครั้ง ฉันพบว่าฉันไม่สามารถยิงกระสุนได้อีกต่อไป ทางที่ดีควรเคลื่อนที่ในขณะที่ยังยิงกระสุนอยู่
การเล่นเกมด้วย Canvas ค่อนข้างน่าสนใจ นอกจากนี้ เกมนี้ยังสามารถขยายและเปลี่ยนเป็นเวอร์ชันมือถือได้ โดยขนาด Canvas จะถูกกำหนดโดยการรับความกว้างและความสูงของหน้าจอ ส่วนแป้นพิมพ์จะเปลี่ยนเป็นกิจกรรมแบบสัมผัส (touchstart, touchmove) , สัมผัส) สามารถเปลี่ยนรูปลักษณ์ของสัตว์ประหลาดได้โดยการสุ่มตกลงมาจากด้านบนของหน้าจอและสัตว์ประหลาดจะเพิ่มพลังชีวิต (เช่น มันจะหายไปหลังจากการยิง 4 ครั้ง) เป็นต้น
ที่อยู่ดาวน์โหลด: https://github.com/littleyljy/shoot
ข้างต้นคือเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการศึกษาของทุกคน ฉันหวังว่าทุกคนจะสนับสนุน VeVb Wulin Network