--- tags: 程式設計作業 --- # 太空除蟲專家與他的太空狗狗 ![](https://hackmd.io/_uploads/SJ63y3r8h.jpg) 玩家將扮演一位太空除蟲專家,太空狗狗們是玩家的好夥伴。 * 射擊到太空狗狗將會被扣5分 * 擊殺太空害蟲可以獲得10分 * 飛船碰撞到太空害蟲,害蟲會死掉,但會扣5分 * 太空害蟲逃出遊戲視窗也會扣10分 * 當分數歸零時遊戲結束 # 作業答案 ## 產生多個元件(class) ![](https://hackmd.io/_uploads/B1L9pZ7U3.png) <iframe width="600" height="800" src="https://www.youtube.com/embed/qvdTK_F93Gs" title="【p5.js練習】怪物生成" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe> #### 程式碼 ```javascript= // 宣告陣列 let enemies = []; // 儲存音效物件的變數 let bgMusic; // 儲存圖片物件的變數 let backgroundImg; // 追蹤生成敵人的時間(毫秒) let enemyTimer = 0; function preload() { // 預載入音效 backgroundImg = loadImage('image/background.png'); enemyImg = loadImage('image/insect.png'); bgMusic = loadSound('music/space_bgm.mp3'); } function setup() { // 設置畫布 createCanvas(600, 800); enemyTimer = millis(); bgMusic.loop(); } function draw() { // 繪製背景 background(backgroundImg); // 每1.5秒生成敵人 if (millis() - enemyTimer > 1500) { let enemy = new Enemy(); enemies.push(enemy); enemyTimer = millis(); } // 移動並顯示敵人 for (let enemy of enemies) { enemy.move(); enemy.display(); } } class Enemy { constructor() { this.x = random(50, width - 70); // 設定敵人的 x 座標為在一定範圍內的隨機數值 this.y = 0; // 設定敵人的 y 座標為 0,即位於畫面上方 this.speed = random(2, 4); // 設定敵人的速度為在一定範圍內的隨機數值 } move() { this.y += this.speed; // 讓敵人往下移動,y 座標加上速度值 } display() { image(enemyImg, this.x, this.y, 100, 104); // 顯示敵人圖片,設定 x 和 y 座標,寬度和高度 } } ``` --- ## 作答內容 ### 以下每個項目,請都要用gif圖片與程式碼表達出來 --- ### class的constructor定義內容 #### Ally.js 實際的程式碼 ```javascript= class Ally { // class 定義了物件的屬性(資料)和方法(行為) constructor() { // 初始化物件的屬性 this.x = random(50, width - 70); // 在畫布的指定範圍內隨機設定 x 座標 this.y = 0; // 設定初始的 y 座標為 0 this.speed = random(2, 4); // 隨機設定移動速度 } } ``` #### Bullet.js 實際的程式碼 ```javascript= class Bullet { constructor(x, y) { this.x = x + 20; // 設定子彈的 x 座標為玩家的 x 座標加上 20 this.y = y - 20; // 設定子彈的 y 座標為玩家的 y 座標減去 20 this.speed = 6; // 設定子彈的速度為 6 } } ``` #### Enemy.js 實際的程式碼 ```javascript= class Enemy { constructor() { this.x = random(50, width - 70); // 設定敵人的 x 座標為在一定範圍內的隨機數值 this.y = 0; // 設定敵人的 y 座標為 0,即位於畫面上方 this.speed = random(2, 4); // 設定敵人的速度為在一定範圍內的隨機數值 } } ``` #### Player.js 實際的程式碼 ```javascript= class Player { constructor() { this.x = width / 2; // 設定玩家的 x 座標為畫面寬度的一半,將玩家置中 this.y = height - 50; // 設定玩家的 y 座標為畫面高度減去 50,即位於畫面下方 this.speed = 8; // 設定玩家的移動速度 this.direction = { left: false, right: false, up: false, down: false // 設定玩家的移動方向,初始值皆為 false }; } ``` --- ### class的畫圖程式碼 #### Ally.js 實際的程式碼 ```javascript= class Ally { // class 定義了物件的屬性(資料)和方法(行為) constructor() { // 初始化物件的屬性 this.x = random(50, width - 70); // 在畫布的指定範圍內隨機設定 x 座標 this.y = 0; // 設定初始的 y 座標為 0 this.speed = random(2, 4); // 隨機設定移動速度 } display() { // 顯示 image(allyImg, this.x, this.y, 100, 100); // 顯示太空狗狗在指定座標位置,大小為 100x100 像素 } } ``` #### Bullet.js 實際的程式碼 ```javascript= class Bullet { constructor(x, y) { this.x = x + 20; // 設定子彈的 x 座標為玩家的 x 座標加上 20 this.y = y - 20; // 設定子彈的 y 座標為玩家的 y 座標減去 20 this.speed = 6; // 設定子彈的速度為 6 } display() { image(bulletImg, this.x + 40, this.y, 10, 30); // 顯示子彈圖片,設定 x 和 y 座標偏移量,寬度和高度 } } ``` #### Enemy.js 實際的程式碼 ```javascript= class Enemy { constructor() { this.x = random(50, width - 70); // 設定敵人的 x 座標為在一定範圍內的隨機數值 this.y = 0; // 設定敵人的 y 座標為 0,即位於畫面上方 this.speed = random(2, 4); // 設定敵人的速度為在一定範圍內的隨機數值 } display() { image(enemyImg, this.x, this.y, 100, 104); // 顯示敵人圖片,設定 x 和 y 座標,寬度和高度 } } ``` #### Player.js 實際的程式碼 ```javascript= class Player { constructor() { this.x = width / 2; // 設定玩家的 x 座標為畫面寬度的一半,將玩家置中 this.y = height - 50; // 設定玩家的 y 座標為畫面高度減去 50,即位於畫面下方 this.speed = 8; // 設定玩家的移動速度 this.direction = { left: false, right: false, up: false, down: false // 設定玩家的移動方向,初始值皆為 false }; display() { image(playerImg, this.x, this.y, 130, 140); // 顯示玩家圖片,設定圖片的位置和大小 } } ``` --- ### class的移動內容 #### Ally.js 實際的程式碼 ```javascript= class Ally { // class 定義了物件的屬性(資料)和方法(行為) constructor() { // 初始化物件的屬性 this.x = random(50, width - 70); // 在畫布的指定範圍內隨機設定 x 座標 this.y = 0; // 設定初始的 y 座標為 0 this.speed = random(2, 4); // 隨機設定移動速度 } move() { // 移動 this.y += this.speed; // 根據速度更新 y 座標,使其向下移動 } display() { // 顯示 image(allyImg, this.x, this.y, 100, 100); // 顯示太空狗狗在指定座標位置,大小為 100x100 像素 } } ``` #### Bullet.js 實際的程式碼 ```javascript= class Bullet { constructor(x, y) { this.x = x + 20; // 設定子彈的 x 座標為玩家的 x 座標加上 20 this.y = y - 20; // 設定子彈的 y 座標為玩家的 y 座標減去 20 this.speed = 6; // 設定子彈的速度為 6 } move() { this.y -= this.speed; // 讓子彈往上移動,y 座標減去速度值 } display() { image(bulletImg, this.x + 40, this.y, 10, 30); // 顯示子彈圖片,設定 x 和 y 座標偏移量,寬度和高度 } } ``` #### Enemy.js 實際的程式碼 ```javascript= class Enemy { constructor() { this.x = random(50, width - 70); // 設定敵人的 x 座標為在一定範圍內的隨機數值 this.y = 0; // 設定敵人的 y 座標為 0,即位於畫面上方 this.speed = random(2, 4); // 設定敵人的速度為在一定範圍內的隨機數值 } move() { this.y += this.speed; // 讓敵人往下移動,y 座標加上速度值 } display() { image(enemyImg, this.x, this.y, 100, 104); // 顯示敵人圖片,設定 x 和 y 座標,寬度和高度 } } ``` #### Player.js 實際的程式碼 ```javascript= class Player { constructor() { this.x = width / 2; // 設定玩家的 x 座標為畫面寬度的一半,將玩家置中 this.y = height - 50; // 設定玩家的 y 座標為畫面高度減去 50,即位於畫面下方 this.speed = 8; // 設定玩家的移動速度 this.direction = { left: false, right: false, up: false, down: false // 設定玩家的移動方向,初始值皆為 false }; } move() { if (this.direction.left) { this.x -= this.speed; // 若向左移動的方向為真,將 x 座標減去速度值 } if (this.direction.right) { this.x += this.speed; // 若向右移動的方向為真,將 x 座標加上速度值 } if (this.direction.up) { this.y -= this.speed; // 若向上移動的方向為真,將 y 座標減去速度值 } if (this.direction.down) { this.y += this.speed; // 若向下移動的方向為真,將 y 座標加上速度值 } this.x = constrain(this.x, 0, width); // 限制 x 座標在畫面寬度的範圍內 this.y = constrain(this.y, 0, height); // 限制 y 座標在畫面高度的範圍內 } moveLeft() { this.direction.left = true; // 設定向左移動的方向為真 } moveRight() { this.direction.right = true; // 設定向右移動的方向為真 } moveUp() { this.direction.up = true; // 設定向上移動的方向為真 } moveDown() { this.direction.down = true; // 設定向下移動的方向為真 } stopMoving(direction) { if (direction === "left") { this.direction.left = false; // 停止向左移動 } if (direction === "right") { this.direction.right = false; // 停止向右移動 } if (direction === "up") { this.direction.up = false; // 停止向上移動 } if (direction === "down") { this.direction.down = false; // 停止向下移動 } } display() { image(playerImg, this.x, this.y, 130, 140); // 顯示玩家圖片,設定圖片的位置和大小 } } ``` --- ### 產生20個相同class的元件 #### 以class Ally為例生成20隻太空狗狗 執行後的圖片 ![](https://hackmd.io/_uploads/HyoFczmIh.png) <iframe width="600" height="800" src="https://www.youtube.com/embed/VbWW-rnXhrA" title="【p5.js練習】一次生成20隻太空狗狗" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe> 實際的程式碼 ```javascript= let allies = []; //友軍的陣列,生成的太空狗狗們會在這裡 // 儲存圖片物件的變數 let allyImg; let backgroundImg; // 儲存音效物件的變數 let bgMusic; function preload() { // preload() 是一個預載入函式,用於在遊戲開始前加載圖片和音效 // 預載入圖片和音效 backgroundImg = loadImage('image/background.png'); allyImg = loadImage('image/space_puppy.png'); bgMusic = loadSound('music/space_bgm.mp3'); } function setup() { // setup() 是設置函式,用於初始化遊戲 // 設置畫布 createCanvas(600, 800); for (let i = 0; i < 20; i++) { let ally = new Ally(); allies.push(ally); } bgMusic.loop(); // 使用 loop() 開始無限循環播放背景音樂 } function draw() { // draw() 是繪製函式,用於繪製遊戲畫面 // 繪製遊戲元素 background(backgroundImg); //括號內放入背景圖片 // 移動並顯示盟友 for (let ally of allies) { ally.move(); ally.display(); } } class Ally { // class 定義了物件的屬性(資料)和方法(行為) constructor() { // 初始化物件的屬性 this.x = random(50, width - 70); // 在畫布的指定範圍內隨機設定 x 座標 this.y = 0; // 設定初始的 y 座標為 0 this.speed = random(2, 4); // 隨機設定移動速度 } move() { // 移動 this.y += this.speed; // 根據速度更新 y 座標,使其向下移動 } display() { // 顯示 image(allyImg, this.x, this.y, 100, 100); // 顯示太空狗狗在指定座標位置,大小為 100x100 像素 } } ``` --- ### 元件的大小,元件的左右移動,速度不一 #### 以class Ally為例生成20隻大小、移動方向、速度不同的太空狗狗。 執行後的圖片 ![](https://hackmd.io/_uploads/Bk05emmIh.png) <iframe width="600" height="801" src="https://www.youtube.com/embed/UpyS0jZCUxU" title="【p5.js練習】生成20隻大小、速度、方向不同的太空狗狗" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe> 實際的程式碼 ```javascript= let allies = []; //友軍的陣列,生成的太空狗狗們會在這裡 // 儲存圖片物件的變數 let allyImg; let backgroundImg; // 儲存音效物件的變數 let bgMusic; function preload() { // preload() 是一個預載入函式,用於在遊戲開始前加載圖片和音效 // 預載入圖片和音效 backgroundImg = loadImage('image/background.png'); allyImg = loadImage('image/space_puppy.png'); bgMusic = loadSound('music/space_bgm.mp3'); } function setup() { // setup() 是設置函式,用於初始化遊戲 // 設置畫布 createCanvas(600, 800); for (let i = 0; i < 20; i++) { let ally = new Ally(); allies.push(ally); } bgMusic.loop(); // 使用 loop() 開始無限循環播放背景音樂 } function draw() { // draw() 是繪製函式,用於繪製遊戲畫面 // 繪製遊戲元素 background(backgroundImg); //括號內放入背景圖片 // 移動並顯示盟友 for (let ally of allies) { ally.move(); ally.display(); } } class Ally { constructor() { // 初始化太空狗狗的屬性 this.x = random(50, width - 70); // 在指定範圍內隨機設定 x 座標 this.y = random(50, height - 70); // 在指定範圍內隨機設定 y 座標 this.size = random(30, 150); // 在指定範圍內隨機設定太空狗狗的大小 this.speedX = random(-2, 2); // 在指定範圍內隨機設定太空狗狗在水平方向的速度 this.speedY = random(-2, 2); // 在指定範圍內隨機設定太空狗狗在垂直方向的速度 } move() { // 移動太空狗狗的位置 this.x += this.speedX; // 根據水平速度更新 x 座標 this.y += this.speedY; // 根據垂直速度更新 y 座標 // 設定邊界條件,避免太空狗狗超出畫布範圍 if (this.x < 0) { this.x = 0; // 限制 x 座標不低於 0 this.speedX *= -1; // 反轉水平速度方向 } else if (this.x + this.size > width) { this.x = width - this.size; // 限制 x 座標不超過畫布寬度減去太空狗狗的大小 this.speedX *= -1; // 反轉水平速度方向 } if (this.y < 0) { this.y = 0; // 限制 y 座標不低於 0 this.speedY *= -1; // 反轉垂直速度方向 } else if (this.y + this.size > height) { this.y = height - this.size; // 限制 y 座標不超過畫布高度減去太空狗狗的大小 this.speedY *= -1; // 反轉垂直速度方向 } } display() { // 顯示太空狗狗 image(allyImg, this.x, this.y, this.size, this.size); // 在指定的座標位置顯示太空狗狗,大小為設定的大小 } } ``` --- ## 滑鼠按下之後,消失不見 #### 以class Enemy為例,滑鼠左鍵點擊昆蟲後消失並移出陣列。 ![](https://hackmd.io/_uploads/Sk7wpQmUh.png) ![](https://hackmd.io/_uploads/B1jP67XLh.png) <iframe width="600" height="801" src="https://www.youtube.com/embed/ebKk3OGsVvE" title="【p5.js練習】滑鼠點擊除掉太空害蟲" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe> 實際的程式碼 ```javascript= // 宣告全域變數 let enemies = []; //敵人的陣列,生成的敵軍會在這裡 // 儲存圖片物件的變數 let enemyImg; let backgroundImg; // 儲存音效物件的變數 let bgMusic; let insectDead; // 追蹤生成敵人的時間(毫秒) let enemyTimer = 0; function preload() { // 預載入圖片 backgroundImg = loadImage('image/background.png'); enemyImg = loadImage('image/insect.png'); bgMusic = loadSound('music/space_bgm.mp3'); insectDead = loadSound('music/insect_dead.mp3'); } function setup() { // 設置畫布 createCanvas(600, 800); enemyTimer = millis(); bgMusic.loop(); } function draw() { // 繪製遊戲元素 background(backgroundImg); // 每1.5秒生成敵人 if (millis() - enemyTimer > 1500) { let enemy = new Enemy(); // 每隔 1.5 秒生成一個敵人物件並將其存入 enemies 陣列 enemies.push(enemy); enemyTimer = millis(); } // 移動並顯示敵人 for (let i = enemies.length - 1; i >= 0; i--) { let enemy = enemies[i]; enemy.move(); enemy.display(); } } function mousePressed() { // 檢查是否點擊到敵人並使用滑鼠左鍵 if (mouseButton === LEFT) { for (let i = enemies.length - 1; i >= 0; i--) { let enemy = enemies[i]; if (mouseX > enemy.x && mouseX < enemy.x + 100 && mouseY > enemy.y && mouseY < enemy.y + 104) { insectDead.play(); //子彈射到敵人播放爆炸音效 enemies.splice(i, 1); } } } } class Enemy { constructor() { this.x = random(50, width - 70); // 設定敵人的 x 座標為在一定範圍內的隨機數值 this.y = 0; // 設定敵人的 y 座標為 0,即位於畫面上方 this.speed = random(2, 4); // 設定敵人的速度為在一定範圍內的隨機數值 } move() { this.y += this.speed; // 讓敵人往下移動,y 座標加上速度值 } display() { image(enemyImg, this.x, this.y, 100, 104); // 顯示敵人圖片,設定 x 和 y 座標,寬度和高度 } } ``` --- ## 發射子彈 ![](https://hackmd.io/_uploads/SySHW4mIn.png) <iframe width="600" height="801" src="https://www.youtube.com/embed/04Q_xk89hIc" title="【p5.js練習】太空船發射子彈" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe> 實際的程式碼 ```javascript= // 宣告全域變數 let bullets = []; // 子彈的陣列,相當於彈藥夾 // 儲存圖片物件的變數 let playerImg; let bulletImg; let backgroundImg; // 儲存音效物件的變數 let bgMusic; let shootSound; function preload() { // 預載入圖片 backgroundImg = loadImage('image/background.png'); playerImg = loadImage('image/spaceship.png'); bulletImg = loadImage('image/bullet.png'); bgMusic = loadSound('music/space_bgm.mp3'); shootSound = loadSound('music/shoot.mp3'); } let player; function setup() { // 設置畫布 createCanvas(600, 800); player = new Player(); // 創建一個 Player 物件並將其存入 player 變數 bgMusic.loop(); // 使用 loop() 開始無限循環播放背景音樂 } function draw() { // 繪製遊戲元素 background(backgroundImg); // 括號內放入背景圖片 // 移動並顯示玩家 player.move(); player.display(); // 移動並顯示子彈 for (let i = bullets.length - 1; i >= 0; i--) { let bullet = bullets[i]; bullet.move(); bullet.display(); // 檢查子彈是否超出畫面,若是則從陣列中刪除該子彈 if (bullet.y < 0) { bullets.splice(i, 1); } } } function keyPressed() { // 按下空白鍵時射擊子彈 if (keyCode === 32) { shootSound.play(); // 播放射擊音效並創建一個子彈物件 let bullet = new Bullet(player.x + 60, player.y); // 將其存入 bullets 陣列 bullets.push(bullet); } // 使用方向鍵或 WASD 鍵移動玩家 if (keyCode === LEFT_ARROW || keyCode === 65) { player.setDirection('left', true); } else if (keyCode === RIGHT_ARROW || keyCode === 68) { player.setDirection('right', true); } else if (keyCode === UP_ARROW || keyCode === 87) { player.setDirection('up', true); } else if (keyCode === DOWN_ARROW || keyCode === 83) { player.setDirection('down', true); } } function keyReleased() { // 當方向鍵或 WASD 鍵被釋放時停止移動玩家 if (keyCode === LEFT_ARROW || keyCode === 65) { player.setDirection('left', false); } else if (keyCode === RIGHT_ARROW || keyCode === 68) { player.setDirection('right', false); } else if (keyCode === UP_ARROW || keyCode === 87) { player.setDirection('up', false); } else if (keyCode === DOWN_ARROW || keyCode === 83) { player.setDirection('down', false); } } class Bullet { constructor(x, y) { this.x = x; // 設定子彈的 x 座標為玩家的 x 座標 this.y = y; // 設定子彈的 y 座標為玩家的 y 座標 this.speed = 6; // 設定子彈的速度為 6 } move() { this.y -= this.speed; // 讓子彈往上移動,y 座標減去速度值 } display() { image(bulletImg, this.x, this.y, 10, 30); // 顯示子彈圖片,設定 x 和 y 座標,寬度和高度 } } class Player { constructor() { this.x = width / 2; // 設定玩家的 x 座標為畫面寬度的一半,將玩家置中 this.y = height - 50; // 設定玩家的 y 座標為畫面高度減去 50,即位於畫面下方 this.speed = 8; // 設定玩家的移動速度 this.direction = { left: false, right: false, up: false, down: false, }; } setDirection(direction, value) { // 設定移動方向狀態 this.direction[direction] = value; } move() { if (this.direction.left) { this.x -= this.speed; // 若向左移動的方向為真,將 x 座標減去速度值 } if (this.direction.right) { this.x += this.speed; // 若向右移動的方向為真,將 x 座標加上速度值 } if (this.direction.up) { this.y -= this.speed; // 若向上移動的方向為真,將 y 座標減去速度值 } if (this.direction.down) { this.y += this.speed; // 若向下移動的方向為真,將 y 座標加上速度值 } this.x = constrain(this.x, 0, width); // 限制 x 座標在畫面寬度的範圍內 this.y = constrain(this.y, 0, height); // 限制 y 座標在畫面高度的範圍內 } display() { image(playerImg, this.x, this.y, 130, 140); // 顯示玩家圖片,設定圖片的位置和大小 } } ``` --- ## 物件消失不見 ![](https://hackmd.io/_uploads/Skfl7V7Lh.png) <iframe width="600" height="801" src="https://www.youtube.com/embed/z3oIai2hSD0" title="【p5.js練習】尚未加入計分機制的DEMO" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe> 實際的程式碼 ```javascript= // 宣告全域變數 // 宣告陣列 let enemies = []; //敵人的陣列,生成的敵軍會在這裡 let allies = []; //友軍的陣列,生成的太空狗狗們會在這裡 let bullets = []; //子彈的陣列,相當於彈藥夾 // 儲存圖片物件的變數 let playerImg; let enemyImg; let allyImg; let bulletImg; let backgroundImg; // 儲存音效物件的變數 let explosionSound; let barkSound; let shootSound; let bgMusic; let insectDead; // 追蹤生成敵人和盟友的時間(毫秒) let enemyTimer = 0; let allyTimer = 0; function preload() { // preload() 是一個預載入函式,用於在遊戲開始前加載圖片和音效 // 預載入圖片和音效 backgroundImg = loadImage('image/background.png'); playerImg = loadImage('image/spaceship.png'); enemyImg = loadImage('image/insect.png'); allyImg = loadImage('image/space_puppy.png'); bulletImg = loadImage('image/bullet.png'); explosionSound = loadSound('music/enemy_died.mp3'); barkSound = loadSound('music/bark.mp3'); shootSound = loadSound('music/shoot.mp3'); insectDead = loadSound('music/insect_dead.mp3'); bgMusic = loadSound('music/space_bgm.mp3'); } function setup() { // setup() 是設置函式,用於初始化遊戲 // 設置畫布 createCanvas(600, 800); player = new Player(); // 創建一個 Player 物件並將其存入 player 變數 allyTimer = millis(); // 將 allyTimer 設置為目前的時間,用於追蹤生成盟友的時間 enemyTimer = millis(); startTime = millis(); bgMusic.loop(); // 使用 loop() 開始無限循環播放背景音樂 } function draw() { // draw() 是繪製函式,用於繪製遊戲畫面 // 繪製遊戲元素 background(backgroundImg); //括號內放入背景圖片 // 移動並顯示玩家 player.move(); player.display(); // 每1.5秒生成敵人 if (millis() - enemyTimer > 1500) { let enemy = new Enemy(); // 每隔 1.5 秒生成一個敵人物件並將其存入 enemies 陣列 enemies.push(enemy); enemyTimer = millis(); } // 每2.5秒生成盟友 if (millis() - allyTimer > 2500) { let ally = new Ally(); // 每隔 2.5 秒生成一個盟友物件並將其存入 allies 陣列 allies.push(ally); allyTimer = millis(); } // 移動並顯示敵人 for (let enemy of enemies) { enemy.move(); enemy.display(); // 檢查敵人是否與子彈碰撞 for (let bullet of bullets) { if (enemy.hits(bullet)) { explosionSound.play(); //子彈射到敵人播放爆炸音效 enemies.splice(enemies.indexOf(enemy), 1); // 將敵人從陣列中移除一個 bullets.splice(bullets.indexOf(bullet), 1); // 將子彈從陣列中移除一個 break; } } // 檢查敵人是否碰瓷玩家 if (enemy.hits(player)) { insectDead.play(); enemies.splice(enemies.indexOf(enemy), 1); // 碰瓷完敵人馬上肇事逃逸 } // 檢查敵人是否觸碰到畫面底部 if (enemy.y >= height) { insectDead.play(); enemies.splice(enemies.indexOf(enemy), 1); } } // 移動並顯示盟友 for (let ally of allies) { ally.move(); ally.display(); // 檢查狗狗是否與子彈碰撞 for (let bullet of bullets) { if (ally.hits(bullet)) { barkSound.play(); // 狗狗不開心發出汪汪叫聲 allies.splice(allies.indexOf(ally), 1); // 狗狗退場一隻 bullets.splice(bullets.indexOf(bullet), 1); // 子彈沒收一顆 } } } // 移動並顯示子彈 for (let bullet of bullets) { bullet.move(); bullet.display(); } } function keyPressed() { // keyPressed() 是按鍵按下事件的處理函式 // 按下空白鍵時射擊子彈 if (keyCode === 32) { // 如果按下的是空白鍵 (keyCode 32) shootSound.play(); // 播放射擊音效並創建一個子彈物件 let bullet = new Bullet(player.x, player.y); // 將其存入 bullets 陣列 bullets.push(bullet); } // 使用方向鍵或 WASD 鍵移動玩家 if (keyCode === LEFT_ARROW || keyCode === 65) { player.moveLeft(); // 如果按下的是左方向鍵或 A 鍵 (keyCode 65),則移動玩家向左 } else if (keyCode === RIGHT_ARROW || keyCode === 68) { player.moveRight(); // 如果按下的是右方向鍵或 D 鍵 (keyCode 68),則移動玩家向右 } else if (keyCode === UP_ARROW || keyCode === 87) { player.moveUp(); // 如果按下的是上方向鍵或 W 鍵 (keyCode 87),則移動玩家向上 } else if (keyCode === DOWN_ARROW || keyCode === 83) { player.moveDown(); // 如果按下的是下方向鍵或 S 鍵 (keyCode 83),則移動玩家向下 } } function keyReleased() { // keyReleased() 是按鍵釋放事件的處理函式 // 當方向鍵或 WASD 鍵被釋放時停止移動玩家 if (keyCode === LEFT_ARROW || keyCode === 65) { player.stopMoving("left"); } else if (keyCode === RIGHT_ARROW || keyCode === 68) { player.stopMoving("right"); } else if (keyCode === UP_ARROW || keyCode === 87) { player.stopMoving("up"); } else if (keyCode === DOWN_ARROW || keyCode === 83) { player.stopMoving("down"); } } ``` --- ## 計算得分 ![](https://hackmd.io/_uploads/HkRJNE7Lh.png) <iframe width="600" height="801" src="https://www.youtube.com/embed/JCkoSLUv0Qw" title="【p5.js練習】加入計分機制" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe> 實際的程式碼 ```javascript= // 宣告全域變數 // 宣告陣列 let enemies = []; //敵人的陣列,生成的敵軍會在這裡 let allies = []; //友軍的陣列,生成的太空狗狗們會在這裡 let bullets = []; //子彈的陣列,相當於彈藥夾 // 計分 let score = 50; // 為了不讓玩家死太快,初始分數設定為50 // 儲存圖片物件的變數 let playerImg; let enemyImg; let allyImg; let bulletImg; let backgroundImg; // 儲存音效物件的變數 let explosionSound; let barkSound; let shootSound; let bgMusic; let insectDead; // 追蹤生成敵人和盟友的時間(毫秒) let enemyTimer = 0; let allyTimer = 0; function preload() { // preload() 是一個預載入函式,用於在遊戲開始前加載圖片和音效 // 預載入圖片和音效 backgroundImg = loadImage('image/background.png'); playerImg = loadImage('image/spaceship.png'); enemyImg = loadImage('image/insect.png'); allyImg = loadImage('image/space_puppy.png'); bulletImg = loadImage('image/bullet.png'); explosionSound = loadSound('music/enemy_died.mp3'); barkSound = loadSound('music/bark.mp3'); shootSound = loadSound('music/shoot.mp3'); insectDead = loadSound('music/insect_dead.mp3'); bgMusic = loadSound('music/space_bgm.mp3'); } function setup() { // setup() 是設置函式,用於初始化遊戲 // 設置畫布 createCanvas(600, 800); player = new Player(); // 創建一個 Player 物件並將其存入 player 變數 allyTimer = millis(); // 將 allyTimer 設置為目前的時間,用於追蹤生成盟友的時間 enemyTimer = millis(); startTime = millis(); bgMusic.loop(); // 使用 loop() 開始無限循環播放背景音樂 } function draw() { // draw() 是繪製函式,用於繪製遊戲畫面 // 繪製遊戲元素 background(backgroundImg); //括號內放入背景圖片 // 移動並顯示玩家 player.move(); player.display(); // 每1.5秒生成敵人 if (millis() - enemyTimer > 1500) { let enemy = new Enemy(); // 每隔 1.5 秒生成一個敵人物件並將其存入 enemies 陣列 enemies.push(enemy); enemyTimer = millis(); } // 每2.5秒生成盟友 if (millis() - allyTimer > 2500) { let ally = new Ally(); // 每隔 2.5 秒生成一個盟友物件並將其存入 allies 陣列 allies.push(ally); allyTimer = millis(); } // 移動並顯示敵人 for (let enemy of enemies) { enemy.move(); enemy.display(); // 檢查敵人是否與子彈碰撞 for (let bullet of bullets) { if (enemy.hits(bullet)) { explosionSound.play(); //子彈射到敵人播放爆炸音效 score += 10; // 子彈射到敵人+10分 enemies.splice(enemies.indexOf(enemy), 1); // 將敵人從陣列中移除一個 bullets.splice(bullets.indexOf(bullet), 1); // 將子彈從陣列中移除一個 break; } } // 檢查敵人是否碰瓷玩家 if (enemy.hits(player)) { insectDead.play(); score -= 5; // 玩家被碰瓷-5分 enemies.splice(enemies.indexOf(enemy), 1); // 碰瓷完敵人馬上肇事逃逸 } // 檢查敵人是否觸碰到畫面底部 if (enemy.y >= height) { insectDead.play(); score -= 10; // 敵人成功逃跑-10分 enemies.splice(enemies.indexOf(enemy), 1); } } // 移動並顯示盟友 for (let ally of allies) { ally.move(); ally.display(); // 檢查狗狗是否與子彈碰撞 for (let bullet of bullets) { if (ally.hits(bullet)) { barkSound.play(); // 狗狗不開心發出汪汪叫聲 score -= 5; // 誤傷友軍-5分 allies.splice(allies.indexOf(ally), 1); // 狗狗退場一隻 bullets.splice(bullets.indexOf(bullet), 1); // 子彈沒收一顆 } } } // 移動並顯示子彈 for (let bullet of bullets) { bullet.move(); bullet.display(); } // 顯示分數 textSize(20); fill(255); text('Score: ' + score, 10, 30); } function keyPressed() { // keyPressed() 是按鍵按下事件的處理函式 // 按下空白鍵時射擊子彈 if (keyCode === 32) { // 如果按下的是空白鍵 (keyCode 32) shootSound.play(); // 播放射擊音效並創建一個子彈物件 let bullet = new Bullet(player.x, player.y); // 將其存入 bullets 陣列 bullets.push(bullet); } // 使用方向鍵或 WASD 鍵移動玩家 if (keyCode === LEFT_ARROW || keyCode === 65) { player.moveLeft(); // 如果按下的是左方向鍵或 A 鍵 (keyCode 65),則移動玩家向左 } else if (keyCode === RIGHT_ARROW || keyCode === 68) { player.moveRight(); // 如果按下的是右方向鍵或 D 鍵 (keyCode 68),則移動玩家向右 } else if (keyCode === UP_ARROW || keyCode === 87) { player.moveUp(); // 如果按下的是上方向鍵或 W 鍵 (keyCode 87),則移動玩家向上 } else if (keyCode === DOWN_ARROW || keyCode === 83) { player.moveDown(); // 如果按下的是下方向鍵或 S 鍵 (keyCode 83),則移動玩家向下 } } function keyReleased() { // keyReleased() 是按鍵釋放事件的處理函式 // 當方向鍵或 WASD 鍵被釋放時停止移動玩家 if (keyCode === LEFT_ARROW || keyCode === 65) { player.stopMoving("left"); } else if (keyCode === RIGHT_ARROW || keyCode === 68) { player.stopMoving("right"); } else if (keyCode === UP_ARROW || keyCode === 87) { player.stopMoving("up"); } else if (keyCode === DOWN_ARROW || keyCode === 83) { player.stopMoving("down"); } } ``` --- ## 結束後顯示畫面 ![](https://hackmd.io/_uploads/Sy_PEEXL2.png) <iframe width="600" height="801" src="https://www.youtube.com/embed/6SIg97-t0Hc" title="【p5.js練習】完整遊戲DEMO" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe> 實際的程式碼 ```javascript= // 宣告全域變數 // 宣告陣列 let enemies = []; //敵人的陣列,生成的敵軍會在這裡 let allies = []; //友軍的陣列,生成的太空狗狗們會在這裡 let bullets = []; //子彈的陣列,相當於彈藥夾 // 計分 let score = 50; // 為了不讓玩家死太快,初始分數設定為50 // 儲存圖片物件的變數 let playerImg; let enemyImg; let allyImg; let bulletImg; let backgroundImg; // 儲存音效物件的變數 let explosionSound; let barkSound; let shootSound; let bgMusic; let insectDead; // 追蹤生成敵人和盟友的時間(毫秒) let enemyTimer = 0; let allyTimer = 0; // 追蹤遊戲開始和結束時間的變數(毫秒) let startTime; let endTime; function preload() { // preload() 是一個預載入函式,用於在遊戲開始前加載圖片和音效 // 預載入圖片和音效 backgroundImg = loadImage('image/background.png'); playerImg = loadImage('image/spaceship.png'); enemyImg = loadImage('image/insect.png'); allyImg = loadImage('image/space_puppy.png'); bulletImg = loadImage('image/bullet.png'); explosionSound = loadSound('music/enemy_died.mp3'); barkSound = loadSound('music/bark.mp3'); shootSound = loadSound('music/shoot.mp3'); insectDead = loadSound('music/insect_dead.mp3'); bgMusic = loadSound('music/space_bgm.mp3'); } function setup() { // setup() 是設置函式,用於初始化遊戲 // 設置畫布 createCanvas(600, 800); player = new Player(); // 創建一個 Player 物件並將其存入 player 變數 allyTimer = millis(); // 將 allyTimer 設置為目前的時間,用於追蹤生成盟友的時間 enemyTimer = millis(); startTime = millis(); bgMusic.loop(); // 使用 loop() 開始無限循環播放背景音樂 } function draw() { // draw() 是繪製函式,用於繪製遊戲畫面 // 繪製遊戲元素 background(backgroundImg); //括號內放入背景圖片 // 移動並顯示玩家 player.move(); player.display(); // 每1.5秒生成敵人 if (millis() - enemyTimer > 1500) { let enemy = new Enemy(); // 每隔 1.5 秒生成一個敵人物件並將其存入 enemies 陣列 enemies.push(enemy); enemyTimer = millis(); } // 每2.5秒生成盟友 if (millis() - allyTimer > 2500) { let ally = new Ally(); // 每隔 2.5 秒生成一個盟友物件並將其存入 allies 陣列 allies.push(ally); allyTimer = millis(); } // 移動並顯示敵人 for (let enemy of enemies) { enemy.move(); enemy.display(); // 檢查敵人是否與子彈碰撞 for (let bullet of bullets) { if (enemy.hits(bullet)) { explosionSound.play(); //子彈射到敵人播放爆炸音效 score += 10; // 子彈射到敵人+10分 enemies.splice(enemies.indexOf(enemy), 1); // 將敵人從陣列中移除一個 bullets.splice(bullets.indexOf(bullet), 1); // 將子彈從陣列中移除一個 break; } } // 檢查敵人是否碰瓷玩家 if (enemy.hits(player)) { insectDead.play(); score -= 5; // 玩家被碰瓷-5分 enemies.splice(enemies.indexOf(enemy), 1); // 碰瓷完敵人馬上肇事逃逸 } // 檢查敵人是否觸碰到畫面底部 if (enemy.y >= height) { insectDead.play(); score -= 10; // 敵人成功逃跑-10分 enemies.splice(enemies.indexOf(enemy), 1); } } // 移動並顯示盟友 for (let ally of allies) { ally.move(); ally.display(); // 檢查狗狗是否與子彈碰撞 for (let bullet of bullets) { if (ally.hits(bullet)) { barkSound.play(); // 狗狗不開心發出汪汪叫聲 score -= 5; // 誤傷友軍-5分 allies.splice(allies.indexOf(ally), 1); // 狗狗退場一隻 bullets.splice(bullets.indexOf(bullet), 1); // 子彈沒收一顆 } } } // 移動並顯示子彈 for (let bullet of bullets) { bullet.move(); bullet.display(); } // 顯示分數 textSize(20); fill(255); text('Score: ' + score, 10, 30); // 檢查遊戲結束條件 if (score <= 0) { // 當分數歸零時遊戲結束 gameOver(); } } function keyPressed() { // keyPressed() 是按鍵按下事件的處理函式 // 按下空白鍵時射擊子彈 if (keyCode === 32) { // 如果按下的是空白鍵 (keyCode 32) shootSound.play(); // 播放射擊音效並創建一個子彈物件 let bullet = new Bullet(player.x, player.y); // 將其存入 bullets 陣列 bullets.push(bullet); } // 使用方向鍵或 WASD 鍵移動玩家 if (keyCode === LEFT_ARROW || keyCode === 65) { player.moveLeft(); // 如果按下的是左方向鍵或 A 鍵 (keyCode 65),則移動玩家向左 } else if (keyCode === RIGHT_ARROW || keyCode === 68) { player.moveRight(); // 如果按下的是右方向鍵或 D 鍵 (keyCode 68),則移動玩家向右 } else if (keyCode === UP_ARROW || keyCode === 87) { player.moveUp(); // 如果按下的是上方向鍵或 W 鍵 (keyCode 87),則移動玩家向上 } else if (keyCode === DOWN_ARROW || keyCode === 83) { player.moveDown(); // 如果按下的是下方向鍵或 S 鍵 (keyCode 83),則移動玩家向下 } } function keyReleased() { // keyReleased() 是按鍵釋放事件的處理函式 // 當方向鍵或 WASD 鍵被釋放時停止移動玩家 if (keyCode === LEFT_ARROW || keyCode === 65) { player.stopMoving("left"); } else if (keyCode === RIGHT_ARROW || keyCode === 68) { player.stopMoving("right"); } else if (keyCode === UP_ARROW || keyCode === 87) { player.stopMoving("up"); } else if (keyCode === DOWN_ARROW || keyCode === 83) { player.stopMoving("down"); } } function gameOver() { // gameOver() 是遊戲結束的處理函式 endTime = millis(); // 將目前的時間(以毫秒為單位)儲存到 endTime 變數中,用於計算存活時間 let survivalTime = (endTime - startTime) / 1000; // 計算存活時間,將 endTime 減去 startTime,再除以 1000,得到以秒為單位的存活時間 bgMusic.stop(); // 停止播放背景音樂 textSize(50); fill(255); textAlign(CENTER, CENTER); // 設定文字的大小為 50,填充顏色為白色,並設定文字對齊方式為置中 text('GAME OVER', width / 2, height / 2); // 在畫布中央顯示 "GAME OVER" 文字,位置為畫布寬度的一半和高度的一半 textSize(24); text('You survived for ' + floor(survivalTime / 60) + ' minutes and ' + floor(survivalTime % 60) + ' seconds', width / 2, height / 2 + 50); // 在畫布中央顯示存活時間的文字,使用 floor() 函式將存活時間的分鐘數和秒數取整,位置為畫布寬度的一半和高度的一半加上 50 像素 noLoop(); // 停止 draw() 函式的迴圈運行,即不再更新畫面 } ``` # 完整程式碼 ## game.js ```javascript= // 宣告全域變數 // 宣告陣列 let enemies = []; //敵人的陣列,生成的敵軍會在這裡 let allies = []; //友軍的陣列,生成的太空狗狗們會在這裡 let bullets = []; //子彈的陣列,相當於彈藥夾 // 計分 let score = 50; // 為了不讓玩家死太快,初始分數設定為50 // 儲存圖片物件的變數 let playerImg; let enemyImg; let allyImg; let bulletImg; let backgroundImg; // 儲存音效物件的變數 let explosionSound; let barkSound; let shootSound; let bgMusic; let insectDead; // 追蹤生成敵人和盟友的時間(毫秒) let enemyTimer = 0; let allyTimer = 0; // 追蹤遊戲開始和結束時間的變數(毫秒) let startTime; let endTime; function preload() { // preload() 是一個預載入函式,用於在遊戲開始前加載圖片和音效 // 預載入圖片和音效 backgroundImg = loadImage('image/background.png'); playerImg = loadImage('image/spaceship.png'); enemyImg = loadImage('image/insect.png'); allyImg = loadImage('image/space_puppy.png'); bulletImg = loadImage('image/bullet.png'); explosionSound = loadSound('music/enemy_died.mp3'); barkSound = loadSound('music/bark.mp3'); shootSound = loadSound('music/shoot.mp3'); insectDead = loadSound('music/insect_dead.mp3'); bgMusic = loadSound('music/space_bgm.mp3'); } function setup() { // setup() 是設置函式,用於初始化遊戲 // 設置畫布 createCanvas(600, 800); player = new Player(); // 創建一個 Player 物件並將其存入 player 變數 allyTimer = millis(); // 將 allyTimer 設置為目前的時間,用於追蹤生成盟友的時間 enemyTimer = millis(); startTime = millis(); bgMusic.loop(); // 使用 loop() 開始無限循環播放背景音樂 } function draw() { // draw() 是繪製函式,用於繪製遊戲畫面 // 繪製遊戲元素 background(backgroundImg); //括號內放入背景圖片 // 移動並顯示玩家 player.move(); player.display(); // 每1.5秒生成敵人 if (millis() - enemyTimer > 1500) { let enemy = new Enemy(); // 每隔 1.5 秒生成一個敵人物件並將其存入 enemies 陣列 enemies.push(enemy); enemyTimer = millis(); } // 每2.5秒生成盟友 if (millis() - allyTimer > 2500) { let ally = new Ally(); // 每隔 2.5 秒生成一個盟友物件並將其存入 allies 陣列 allies.push(ally); allyTimer = millis(); } // 移動並顯示敵人 for (let enemy of enemies) { enemy.move(); enemy.display(); // 檢查敵人是否與子彈碰撞 for (let bullet of bullets) { if (enemy.hits(bullet)) { explosionSound.play(); //子彈射到敵人播放爆炸音效 score += 10; // 子彈射到敵人+10分 enemies.splice(enemies.indexOf(enemy), 1); // 將敵人從陣列中移除一個 bullets.splice(bullets.indexOf(bullet), 1); // 將子彈從陣列中移除一個 break; } } // 檢查敵人是否碰瓷玩家 if (enemy.hits(player)) { insectDead.play(); score -= 5; // 玩家被碰瓷-5分 enemies.splice(enemies.indexOf(enemy), 1); // 碰瓷完敵人馬上肇事逃逸 } // 檢查敵人是否觸碰到畫面底部 if (enemy.y >= height) { insectDead.play(); score -= 10; // 敵人成功逃跑-10分 enemies.splice(enemies.indexOf(enemy), 1); } } // 移動並顯示盟友 for (let ally of allies) { ally.move(); ally.display(); // 檢查狗狗是否與子彈碰撞 for (let bullet of bullets) { if (ally.hits(bullet)) { barkSound.play(); // 狗狗不開心發出汪汪叫聲 score -= 5; // 誤傷友軍-5分 allies.splice(allies.indexOf(ally), 1); // 狗狗退場一隻 bullets.splice(bullets.indexOf(bullet), 1); // 子彈沒收一顆 } } } // 移動並顯示子彈 for (let bullet of bullets) { bullet.move(); bullet.display(); } // 顯示分數 textSize(20); fill(255); text('Score: ' + score, 10, 30); // 檢查遊戲結束條件 if (score <= 0) { // 當分數歸零時遊戲結束 gameOver(); } } function keyPressed() { // keyPressed() 是按鍵按下事件的處理函式 // 按下空白鍵時射擊子彈 if (keyCode === 32) { // 如果按下的是空白鍵 (keyCode 32) shootSound.play(); // 播放射擊音效並創建一個子彈物件 let bullet = new Bullet(player.x, player.y); // 將其存入 bullets 陣列 bullets.push(bullet); } // 使用方向鍵或 WASD 鍵移動玩家 if (keyCode === LEFT_ARROW || keyCode === 65) { player.moveLeft(); // 如果按下的是左方向鍵或 A 鍵 (keyCode 65),則移動玩家向左 } else if (keyCode === RIGHT_ARROW || keyCode === 68) { player.moveRight(); // 如果按下的是右方向鍵或 D 鍵 (keyCode 68),則移動玩家向右 } else if (keyCode === UP_ARROW || keyCode === 87) { player.moveUp(); // 如果按下的是上方向鍵或 W 鍵 (keyCode 87),則移動玩家向上 } else if (keyCode === DOWN_ARROW || keyCode === 83) { player.moveDown(); // 如果按下的是下方向鍵或 S 鍵 (keyCode 83),則移動玩家向下 } } function keyReleased() { // keyReleased() 是按鍵釋放事件的處理函式 // 當方向鍵或 WASD 鍵被釋放時停止移動玩家 if (keyCode === LEFT_ARROW || keyCode === 65) { player.stopMoving("left"); } else if (keyCode === RIGHT_ARROW || keyCode === 68) { player.stopMoving("right"); } else if (keyCode === UP_ARROW || keyCode === 87) { player.stopMoving("up"); } else if (keyCode === DOWN_ARROW || keyCode === 83) { player.stopMoving("down"); } } function gameOver() { // gameOver() 是遊戲結束的處理函式 endTime = millis(); // 將目前的時間(以毫秒為單位)儲存到 endTime 變數中,用於計算存活時間 let survivalTime = (endTime - startTime) / 1000; // 計算存活時間,將 endTime 減去 startTime,再除以 1000,得到以秒為單位的存活時間 bgMusic.stop(); // 停止播放背景音樂 textSize(50); fill(255); textAlign(CENTER, CENTER); // 設定文字的大小為 50,填充顏色為白色,並設定文字對齊方式為置中 text('GAME OVER', width / 2, height / 2); // 在畫布中央顯示 "GAME OVER" 文字,位置為畫布寬度的一半和高度的一半 textSize(24); text('You survived for ' + floor(survivalTime / 60) + ' minutes and ' + floor(survivalTime % 60) + ' seconds', width / 2, height / 2 + 50); // 在畫布中央顯示存活時間的文字,使用 floor() 函式將存活時間的分鐘數和秒數取整,位置為畫布寬度的一半和高度的一半加上 50 像素 noLoop(); // 停止 draw() 函式的迴圈運行,即不再更新畫面 } ``` ## Ally.js ```javascript= class Ally { // class 定義了物件的屬性(資料)和方法(行為) constructor() { // 初始化物件的屬性 this.x = random(50, width - 70); // 在畫布的指定範圍內隨機設定 x 座標 this.y = 0; // 設定初始的 y 座標為 0 this.speed = random(2, 4); // 隨機設定移動速度 } move() { // 移動 this.y += this.speed; // 根據速度更新 y 座標,使其向下移動 } display() { // 顯示 image(allyImg, this.x, this.y, 100, 100); // 顯示太空狗狗在指定座標位置,大小為 100x100 像素 } hits(bullet) { // 碰撞判定方法 let hit = collideRectRect( // collideRectRect() 函式判斷盟友和子彈是否發生碰撞 this.x, // 第一個矩形(太空狗狗)的左上角 x 座標 this.y, // 第一個矩形(太空狗狗)的左上角 y 座標 100, // 第一個矩形的寬度 100, // 第一個矩形的高度 bullet.x, // 第二個矩形(子彈)的左上角 x 座標 bullet.y, // 第二個矩形(子彈)的左上角 y 座標 10, // 第二個矩形的寬度 30 // 第二個矩形的高度 ); return hit; // 判斷盟友和子彈是否發生碰撞,並回傳結果 } } ``` ## Bullet.js ```javascript= class Bullet { constructor(x, y) { this.x = x + 20; // 設定子彈的 x 座標為玩家的 x 座標加上 20 this.y = y - 20; // 設定子彈的 y 座標為玩家的 y 座標減去 20 this.speed = 6; // 設定子彈的速度為 6 } move() { this.y -= this.speed; // 讓子彈往上移動,y 座標減去速度值 } display() { image(bulletImg, this.x + 40, this.y, 10, 30); // 顯示子彈圖片,設定 x 和 y 座標偏移量,寬度和高度 } } ``` ## Enemy.js ```javascript= class Enemy { constructor() { this.x = random(50, width - 70); // 設定敵人的 x 座標為在一定範圍內的隨機數值 this.y = 0; // 設定敵人的 y 座標為 0,即位於畫面上方 this.speed = random(2, 4); // 設定敵人的速度為在一定範圍內的隨機數值 } move() { this.y += this.speed; // 讓敵人往下移動,y 座標加上速度值 } display() { image(enemyImg, this.x, this.y, 100, 104); // 顯示敵人圖片,設定 x 和 y 座標,寬度和高度 } hits(bullet) { let hit = collideRectRect( this.x - 25, // 設定敵人碰撞偵測的矩形左上角 x 座標,將 x 值減去 25 this.y, // 設定敵人碰撞偵測的矩形左上角 y 座標 enemyImg.width, // 設定敵人碰撞偵測的矩形寬度,使用敵人圖片的寬度 enemyImg.height, // 設定敵人碰撞偵測的矩形高度,使用敵人圖片的高度 bullet.x, // 設定子彈碰撞偵測的矩形左上角 x 座標 bullet.y, // 設定子彈碰撞偵測的矩形左上角 y 座標 bulletImg.width, // 設定子彈碰撞偵測的矩形寬度,使用子彈圖片的寬度 bulletImg.height // 設定子彈碰撞偵測的矩形高度,使用子彈圖片的高度 ); return hit; // 回傳碰撞偵測結果 } } ``` ## Player.js ```javascript= class Player { constructor() { this.x = width / 2; // 設定玩家的 x 座標為畫面寬度的一半,將玩家置中 this.y = height - 50; // 設定玩家的 y 座標為畫面高度減去 50,即位於畫面下方 this.speed = 8; // 設定玩家的移動速度 this.direction = { left: false, right: false, up: false, down: false // 設定玩家的移動方向,初始值皆為 false }; } move() { if (this.direction.left) { this.x -= this.speed; // 若向左移動的方向為真,將 x 座標減去速度值 } if (this.direction.right) { this.x += this.speed; // 若向右移動的方向為真,將 x 座標加上速度值 } if (this.direction.up) { this.y -= this.speed; // 若向上移動的方向為真,將 y 座標減去速度值 } if (this.direction.down) { this.y += this.speed; // 若向下移動的方向為真,將 y 座標加上速度值 } this.x = constrain(this.x, 0, width); // 限制 x 座標在畫面寬度的範圍內 this.y = constrain(this.y, 0, height); // 限制 y 座標在畫面高度的範圍內 } moveLeft() { this.direction.left = true; // 設定向左移動的方向為真 } moveRight() { this.direction.right = true; // 設定向右移動的方向為真 } moveUp() { this.direction.up = true; // 設定向上移動的方向為真 } moveDown() { this.direction.down = true; // 設定向下移動的方向為真 } stopMoving(direction) { if (direction === "left") { this.direction.left = false; // 停止向左移動 } if (direction === "right") { this.direction.right = false; // 停止向右移動 } if (direction === "up") { this.direction.up = false; // 停止向上移動 } if (direction === "down") { this.direction.down = false; // 停止向下移動 } } display() { image(playerImg, this.x, this.y, 130, 140); // 顯示玩家圖片,設定圖片的位置和大小 } } ``` ## index.html ```html= <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Space Pest Control Expert and their Space Dog</title> <link rel="stylesheet" type="text/css" href="style.css"> <script src="libraries/p5.min.js"></script> <script src="libraries/p5.sound.min.js"></script> <script src="libraries/p5.collide2d.min.js"></script> </head> <body> <script src="game.js"></script> <script src="Player.js"></script> <script src="Enemy.js"></script> <script src="Ally.js"></script> <script src="Bullet.js"></script> </body> </html> ``` ## style.css ```css= html, body { margin: 0; padding: 0; } canvas { display: block; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } ```