Vue3集成Phaser-飛機大戰游戲(設計與源碼)

在這里插入圖片描述

文章目錄

  • 引言
  • 項目初始化
  • 游戲設計和結構
  • 游戲程序實現
    • Vue頁面嵌入Phaser
    • Preloader 場景加載
    • 游戲場景功能實現
    • 功能類定義
      • Boom爆炸類
      • Bullet子彈類
      • Enemy敵軍類
      • Player玩家類
      • End游戲結束類
  • 總結

更多相關內容可查看

引言

飛機大戰(也被稱為射擊游戲或空戰游戲)是一種非常受歡迎的休閑游戲類型。在這個博客中,我們將探討如何使用 Vue.js 框架來構建一個簡單的飛機大戰游戲。我們將從基本的游戲邏輯開始,逐步增加游戲元素和交互性,代碼詳解可參考注釋,最終展示畫面在文章底部

項目初始化

git地址:https://gitee.com/its-a-little-bad/vue-project—aircraft-battle.git
node版本:20.8.1

游戲設計和結構

在 Vue.js 中,我們通常將游戲的各個部分分解為不同的場景。

主場景

Game.vue:游戲的主界面,包含背景、飛機、敵機、子彈等。
Plane.vue:玩家的飛機,可以移動和發射子彈。
Enemy.vue:敵機,從屏幕上方隨機出現并向下移動。
Bullet.vue:子彈,從玩家飛機發射并向上移動。

游戲場景
在這里插入圖片描述

游戲程序實現

Vue頁面嵌入Phaser

在 Vue 應用中嵌入一個 Phaser 游戲

<template><!-- Phaser 游戲的容器 --><div id="container"></div>
</template>
<script setup lang="ts">
import { onMounted, onUnmounted } from "vue";
import { Game, AUTO, Scale } from "phaser";
import { Preloader } from "./game/Preloader";
import { Main } from "./game/Main";
import { End } from "./game/End";// 使用正則表達式檢測當前設備是否為移動設備
let isMobile = /(iPhone|iPad|Android)/i.test(navigator.userAgent);// 定義了一個 game 變量來存儲 Phaser 游戲實例
let game: Game;
onMounted(() => {game = new Game({parent: "container",type: AUTO,width: 375,//游戲的大小根據設備類型進行調整。如果設備是移動設備,則高度會根據設備的縱橫比計算得出。height: isMobile ? (window.innerHeight / window.innerWidth) * 375 : 667,//游戲的縮放模式也根據設備類型進行設置。移動設備使用 Scale.FIT,這意味著游戲將盡可能地適應屏幕大小,//而不會保持其原始縱橫比。非移動設備則使用 Scale.NONE,這意味著游戲將保持其原始大小。scale: {mode: isMobile ? Scale.FIT : Scale.NONE,},physics: {default: "arcade",arcade: {debug: false,},},scene: [Preloader, Main, End],});
});onUnmounted(() => {game.destroy(true);
});
</script><style>
body {margin: 0;
}
#app {height: 100%;
}
</style>

Preloader 場景加載

創建一個 Preloader 場景來加載游戲所需的資源和設置一些基本的游戲元素,示例如下
在這里插入圖片描述
程序實現:

import { Scene } from "phaser";  
import backgroundImg from "../assets/images/background.jpg";  
import enemyImg from "../assets/images/enemy.png";  
import playerImg from "../assets/images/player.png";  
import bulletImg from "../assets/images/bullet.png";  
import boomImg from "../assets/images/boom.png";  
import spritesImg from "../assets/images/sprites.png";  
import spritesJson from "../assets/json/sprites.json?url";  
import bgmAudio from "../assets/audio/bgm.mp3";  
import boomAudio from "../assets/audio/boom.mp3";  
import bulletAudio from "../assets/audio/bullet.mp3";  export class Preloader extends Scene {  // 構造函數,定義場景名稱為 "Preloader"  constructor() {  super("Preloader");  }  // 預加載資源的方法  preload() {  // 加載背景圖片  this.load.image("background", backgroundImg);  // 加載敵人圖片  this.load.image("enemy", enemyImg);  // 加載玩家圖片  this.load.image("player", playerImg);  // 加載子彈圖片  this.load.image("bullet", bulletImg);  // 加載爆炸動畫的精靈表(spritesheet)  this.load.spritesheet("boom", boomImg, {  frameWidth: 64,  frameHeight: 48,  });  // 加載精靈圖集(atlas)  this.load.atlas("sprites", spritesImg, spritesJson);  // 加載背景音樂  this.load.audio("bgm", bgmAudio);  // 加載爆炸音效  this.load.audio("boom", boomAudio);  // 加載子彈音效  this.load.audio("bullet", bulletAudio);  }  // 創建場景的方法  create() {  const { width, height } = this.cameras.main;  // 顯示背景(通常在Preloader場景中不展示實際游戲內容,這里僅為示例)  this.add.tileSprite(0, 0, width, height, "background").setOrigin(0, 0);  // 播放背景音樂(在Preloader場景中播放通常是為了給玩家一個等待的反饋)  this.sound.play("bgm", { loop: true }); // 循環播放背景音樂  // 添加標題(通常也不在Preloader場景中,但可以作為加載提示)  this.add  .text(width / 2, height / 4, "飛機大戰", {  fontFamily: "Arial",  fontSize: 60,  color: "#e3f2ed",  stroke: "#203c5b",  strokeThickness: 6,  })  .setOrigin(0.5);  // 添加開始按鈕(通常用于在加載完成后切換到主場景)  let button = this.add  .image(width / 2, (height / 4) * 3, "sprites", "button") // 假設"sprites"圖集中有名為"button"的幀  .setScale(3, 2)  .setInteractive()  .on("pointerdown", () => {  // 當按鈕被點擊時,切換到主場景(這里主場景名為'Main')  this.scene.start('Main');  });  // 按鈕文案this.add.text(button.x, button.y, "開始游戲", {fontFamily: "Arial",fontSize: 20,color: "#e3f2ed",}).setOrigin(0.5); }  // 創建動畫,命名為 boom,后面使用this.anims.create({key: "boom",frames: this.anims.generateFrameNumbers("boom", { start: 0, end: 18 }),repeat: 0,});
}

在Phaser 3框架中,從一個場景(如Preloader)切換到另一個場景(如Main)通常使用this.scene.start(‘Main’)這樣的代碼來實現。這是Phaser場景管理系統的一部分,它允許你動態地加載、創建、運行和銷毀游戲的不同部分。

游戲場景功能實現

在這里插入圖片描述

程序實現

// 定義 Main 場景類,繼承自 Phaser 的 Scene 類  
import { Scene, Physics, GameObjects } from "phaser";
import { Player } from "./Player";
import { Bullet } from "./Bullet";
import { Enemy } from "./Enemy";
import { Boom } from "./Boom";// 場景元素
let background: GameObjects.TileSprite;
let player: Player;
let enemys: Physics.Arcade.Group;
let bullets: Physics.Arcade.Group;
let booms: GameObjects.Group;
let scoreText: GameObjects.Text;// 場景數據
let score: number;export class Main extends Scene {constructor() {super("Main");}create() {let { width, height } = this.cameras.main;// 創建背景background = this.add.tileSprite(0, 0, width, height, "background").setOrigin(0, 0);// 創建玩家,調用Player類player = new Player(this);// 創建敵軍組// 注解:enemys 是一個 Phaser 的物理組,用于存儲和管理多個 Enemy 對象// frameQuantity 表示從 enemy 紋理集中加載的幀數,key 是紋理集的名稱// enable, active, visible 分別是啟用物理、激活和可見性標志// classType 指示組中新創建對象的類型enemys = this.physics.add.group({frameQuantity: 30,key: "enemy",enable: false,// 在此初始狀態下不啟用物理 active: false,// 在此初始狀態下不激活  visible: false,// 在此初始狀態下不可見classType: Enemy,// 當組中添加新對象時使用的類});// 創建子彈// 注解:與敵軍組類似,但用于存儲和管理多個 Bullet 對象 bullets = this.physics.add.group({frameQuantity: 15,key: "bullet",enable: false,active: false,visible: false,classType: Bullet,});// 創建爆炸// 注解:booms 組用于存儲和管理多個 Boom 對象,可能是用于顯示爆炸動畫booms = this.add.group({frameQuantity: 30,key: "boom",active: false,visible: false,classType: Boom,});// 分數// 注解:score 變量用于跟蹤玩家的分數,scoreText 是顯示分數的文本對象 score = 0;scoreText = this.add.text(10, 10, "0", {fontFamily: "Arial",fontSize: 20,});// 注冊事件this.addEvent();}// 注冊事件addEvent() {// 定時器// 注解:此定時器每 400 毫秒觸發一次回調,生成敵軍和發射子彈 this.time.addEvent({delay: 400,callback: () => {// 生成2個敵軍for (let i = 0; i < 2; i++) {enemys.getFirstDead()?.born();}// 發射1顆子彈bullets.getFirstDead()?.fire(player.x, player.y - 32);},callbackScope: this,repeat: -1,});// 子彈和敵軍碰撞,會調用 hit 方法this.physics.add.overlap(bullets, enemys, this.hit, null, this);// 玩家和敵軍碰撞,會調用 gameOver 方法this.physics.add.overlap(player, enemys, this.gameOver, null, this);}// 子彈擊中敵軍hit(bullet, enemy) {// 子彈和敵軍隱藏enemy.disableBody(true, true);bullet.disableBody(true, true);// 顯示爆炸booms.getFirstDead()?.show(enemy.x, enemy.y);// 分數增加scoreText.text = String(++score);}// 游戲結束gameOver() {// 暫停當前場景,并沒有銷毀this.sys.pause();// 保存分數this.registry.set("score", score);// 打開結束場景this.game.scene.start("End");}update() {// 設置背景瓦片不斷移動background.tilePositionY -= 1;}
}

功能類定義

Boom爆炸類

import { GameObjects, Scene } from "phaser";export class Boom extends GameObjects.Sprite {constructor(scene: Scene, x: number, y: number, texture: string) {// 創建對象super(scene, x, y, texture);// 爆炸動畫播放結束事件this.on("animationcomplete-boom", this.hide, this);}/*** 顯示爆炸* @param x 爆炸x坐標* @param y 爆炸y坐標*/show(x: number, y: number) {this.x = x;this.y = y;this.setActive(true);this.setVisible(true);// 爆炸動畫this.play("boom");// 爆炸音效this.scene.sound.play("boom");}/*** 隱藏爆炸*/hide() {this.setActive(false);this.setVisible(false);}
}

Bullet子彈類

import { Physics, Scene } from "phaser";export class Bullet extends Physics.Arcade.Sprite {constructor(scene: Scene, x: number, y: number, texture: string) {super(scene, x, y, texture);// 設置屬性this.setScale(0.25);}/*** 發射子彈* @param x 子彈x坐標* @param y 子彈y坐標*/fire(x: number, y: number) {this.enableBody(true, x, y, true, true);this.setVelocityY(-300);this.scene.sound.play("bullet");}preUpdate(time: number, delta: number) {super.preUpdate(time, delta);// 子彈走到頭,銷毀if (this.y <= -14) {this.disableBody(true, true);}}
}

Enemy敵軍類

import { Physics, Math, Scene } from "phaser";export class Enemy extends Physics.Arcade.Sprite {constructor(scene: Scene, x: number, y: number, texture: string) {// 創建對象super(scene, x, y, texture);scene.add.existing(this);scene.physics.add.existing(this);// 設置屬性this.setScale(0.5);this.body.setSize(100, 60);}/*** 生成敵軍*/born() {let x = Math.Between(30, 345);let y = Math.Between(-20, -40);this.enableBody(true, x, y, true, true);this.setVelocityY(Math.Between(150, 300));}preUpdate(time: number, delta: number) {super.preUpdate(time, delta);let { height } = this.scene.cameras.main;// 敵軍走到頭,銷毀if (this.y >= height + 20) {this.disableBody(true, true)}}
}

Player玩家類

import { Physics, Scene } from "phaser";export class Player extends Physics.Arcade.Sprite {isDown: boolean = false;downX: number;downY: number;constructor(scene: Scene) {// 創建對象let { width, height } = scene.cameras.main;super(scene, width / 2, height - 80, "player");scene.add.existing(this);scene.physics.add.existing(this);// 設置屬性this.setInteractive();this.setScale(0.5);this.setCollideWorldBounds(true);this.body.setSize(120, 120);// 注冊事件this.addEvent();}/*** 注冊事件*/addEvent() {// 手指按下我方飛機this.on("pointerdown", () => {this.isDown = true;this.downX = this.x;this.downY = this.y;});// 手指抬起this.scene.input.on("pointerup", () => {this.isDown = false;});// 手指移動this.scene.input.on("pointermove", (pointer) => {if (this.isDown) {this.x = this.downX + pointer.x - pointer.downX;this.y = this.downY + pointer.y - pointer.downY;}});}
}

End游戲結束類

import { Scene } from "phaser";export class End extends Scene {constructor() {super("End");}create() {let { width, height } = this.cameras.main;// 結束面板this.add.image(width / 2, height / 2, "sprites", "result").setScale(2.5);// 標題this.add.text(width / 2, height / 2 - 85, "游戲結束", {fontFamily: "Arial",fontSize: 24,}).setOrigin(0.5);// 當前得分let score = this.registry.get("score");this.add.text(width / 2, height / 2 - 10, `當前得分:${score}`, {fontFamily: "Arial",fontSize: 20,}).setOrigin(0.5);// 重新開始按鈕let button = this.add.image(width / 2, height / 2 + 50, "sprites", "button").setScale(3, 2).setInteractive().on("pointerdown", () => {// 點擊事件:關閉當前場景,打開Main場景this.scene.start("Main");});// 按鈕文案this.add.text(button.x, button.y, "重新開始", {fontFamily: "Arial",fontSize: 20,}).setOrigin(0.5);}
}

總結

通過使用 Vue.js 框架,我們可以輕松地構建出一個簡單而有趣的飛機大戰游戲。從基本的游戲邏輯開始,逐步增加游戲元素和交互性,最終得到一個完整且吸引人的游戲作品。希望這個博客能對你有所啟發,并鼓勵你嘗試使用 Vue.js 來開發更多有趣的游戲和應用程序!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/21079.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/21079.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/21079.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

輕松上手MYSQL:優化MySQL慢查詢,讓數據庫起飛

?&#x1f308; 個人主頁&#xff1a;danci_ &#x1f525; 系列專欄&#xff1a;《設計模式》《MYSQL應用》 &#x1f4aa;&#x1f3fb; 制定明確可量化的目標&#xff0c;堅持默默的做事。 ?歡迎加入探索MYSQL慢查詢之旅? &#x1f44b; 大家好&#xff01;我是你們的…

如何優雅簡潔的使用YOLOv8

如何優雅簡潔的使用YOLOv8 目錄訓練調用代碼如何一鍵訓練多個yamlexport模型測試多個yaml是否運行正常predict本文提供了 如何優雅簡潔的使用YOLOv8 ???YOLOv8實戰寶典--星級指南:從入門到精通,您不可錯過的技巧 ??-- 聚焦于YOLO的 最新版本, 對頸部網絡改進、添加局…

Crosslink-NX器件應用連載(11): 圖像(數據)遠程傳輸

作者&#xff1a;Hello&#xff0c;Panda 大家下午好&#xff0c;晚上好。這里分享一個Lattice Crosslink-NX器件實現圖像或數據&#xff08;衛星數據、雷達數據、ToF傳感器數據等&#xff09;遠程傳輸的案例&#xff08;因為所描述的內容頗雜&#xff0c;曬圖不好曬&#xff…

react自用小技巧(持續更新中)

react自用小技巧&#xff08;持續更新中&#xff09; 作者&#xff1a;devwolf 導言&#xff1a; 筆者應屆時&#xff0c;投vue2就任一家大食品廠的資訊部后轉成了react&#xff0c;寫了一年出頭的react類組件。然后跳槽到蘇州科技城的一個原做影視渲染的公司開始全面轉hook…

文件批量改后綴名,輕松實現TXT到DOCX格式轉換,高效管理您的文件庫!

文件處理與管理已成為我們日常生活和工作中不可或缺的一環。然而&#xff0c;面對海量的文件&#xff0c;如何高效地進行格式轉換和管理&#xff0c;卻成為了一道難題。今天&#xff0c;我們將為您揭曉一個神奇的解決方案——文件批量改后綴名功能&#xff0c;讓您輕松實現TXT到…

【GPT-4o:開創人工智能新紀元】

GPT-4o&#xff1a;開創人工智能新紀元 最近&#xff0c;GPT-4o問世&#xff0c;再次引發了人們對人工智能技術的關注和討論。這一新型語言模型的出現&#xff0c;不僅在技術上實現了飛躍&#xff0c;也為我們帶來了全新的思考和體驗。接下來&#xff0c;我們將對GPT-4o進行全…

【docker】docker的安裝

如果之前安裝了舊版本的docker我們需要進行卸載&#xff1a; 卸載之前的舊版本 卸載 # 卸載舊版本 sudo apt-get remove docker docker-engine docker.io containerd runc # 卸載歷史版本 apt-get purge docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker…

linux文件共享之samba

1.介紹 Samba是一個開源文件共享服務&#xff0c;可以使linux與windows之間進行文件共享&#xff0c;可以根據不同人員調整共享設置以及權限管理。 2.安裝 一個命令就OK了&#xff1a;yum install -y samba [rootansible01 ~]# yum install -y samba 已加載插件&#xff1a;l…

Python爬蟲之簡單學習BeautifulSoup庫,學習獲取的對象常用方法,實戰豆瓣Top250

BeautifulSoup是一個非常流行的Python庫&#xff0c;廣泛應用于網絡爬蟲開發中&#xff0c;用于解析HTML和XML文檔&#xff0c;以便于從中提取所需數據。它是進行網頁內容抓取和數據挖掘的強大工具。 功能特性 易于使用: 提供簡潔的API&#xff0c;使得即使是對網頁結構不熟悉…

【一刷《劍指Offer》】面試題 31:連續子數組的最大和

牛客對應題目鏈接&#xff1a;連續子數組最大和_牛客題霸_牛客網 (nowcoder.com) 力扣對應題目鏈接&#xff1a;53. 最大子數組和 - 力扣&#xff08;LeetCode&#xff09; 核心考點 &#xff1a;簡單動歸問題。 一、《劍指Offer》對應內容 二、分析題目 1、貪心 從前往后迭…

backbone主干網絡的選取

backbone_name 通常用于指定深度學習模型的主干網絡&#xff08;backbone network&#xff09;。主干網絡是指在整個模型中承擔主要特征提取任務的部分。不同的主干網絡有不同的架構和特征提取能力&#xff0c;適用于不同的任務和數據集。 針對戴著口罩和戴著3D眼睛提取人臉特征…

關于Posix標準接口和Nuttx操作系統

基本介紹 主要參考&#xff1a; Linux 系統中的 POSIX 接口詳細介紹_linux posix-CSDN博客 POSIX&#xff08;Portable Operating System Interface&#xff0c;可移植操作系統接口&#xff09;是由 IEEE&#xff08;Institute of Electrical and Electronics Engineers&#x…

大模型對齊方法筆記四:針對領域問答來進行知識對齊方法KnowPAT

KnowPAT KnowPAT(Knowledgeable Preference AlignmenT) 出自2023年11月的論文《Knowledgeable Preference Alignment for LLMs in Domain-specific Question Answering》&#xff0c;主要針對領域問答來進行知識對齊。 在領域問答有兩個挑戰&#xff1a;希望輸出滿足用戶的要…

Notepad++ 常用

File Edit search view Encoding Language Settings Tools Macro Run Plugins Window 文件 編輯 搜索 視圖 編碼 語言 設置 工具 宏 運行 插件 窗口 快捷方式 定位行 &#xff1a;CTRL g查找&#xff1a; CTRL F替換&am…

小白也能看得懂的基于HTML+CSS+JS實現的五子棋小游戲

五子棋是一種起源于中國的傳統棋類游戲&#xff0c;具有悠久的歷史。 基本規則 棋盤&#xff1a; 五子棋通常在一個 15x15 的棋盤上進行&#xff0c;但也可以在更大的棋盤上進行。棋盤上的每個交叉點稱為一個“點”。 棋子&#xff1a; 五子棋使用黑白兩色的棋子。兩名玩家分別…

【競技寶】歐冠:多特搶開局失敗,皇馬展示頂級防守反擊

本賽季歐冠決賽結束,皇馬在上半場被壓制的情況下,2比0擊敗多特蒙德奪得隊史第15座歐冠冠軍獎杯。比賽中多特蒙德已經展現出了不俗的狀態,可是面對老辣的皇馬他們還是敗下陣來,皇馬用頂級的防守反擊給多特上了一課。通過這場比賽,相信球迷們也清楚當今足壇硬實力不可或缺。 在許…

《Effective C++》《資源管理——14、在資源管理類中小心copying行為》

文章目錄 1、Terms14:Think carefully about copying behavior in resource-managing classes方法一&#xff1a;禁止復制方法二&#xff1a;對底層資源使出“引用計數法”方法三&#xff1a;復制底部資源方法四&#xff1a;轉移底部資源的擁有權 2、總結3、參考 1、Terms14:Th…

7-18 對象關系映射(orm_name)---PTA實驗C++

一、題目描述 一開始看到對象關系映射&#xff0c;其實我是拒絕的。這三個詞湊一塊&#xff0c;能是給C初學者的題嗎&#xff1f; 再仔細讀需求&#xff0c;才發現在課設項目已經用過這功能。Object Relational Mapping&#xff08;ORM&#xff09;就是面向對象&#xff08;O…

計算機基礎之:LSM樹

使用過hbase、cassandra之類nosql數據庫的小伙伴對LSM樹結構應該有所耳聞&#xff0c;那么這種數據結構有哪些優劣勢呢&#xff0c;本文做下簡單介紹。 LSM&#xff08;全稱&#xff1a;Log-Structured Merge Tree&#xff09;是一種廣泛應用于現代數據庫和存儲系統的數據結構…

《平淵》· 柒 —— 大道至簡?真傳一句話,假傳萬卷書!

《平淵》 柒 "真傳一句話, 假傳萬卷書" 對于 "大道至簡"&#xff0c;不少專家可能會說出一大堆亂七八糟的名詞, 比如這樣&#xff1a; 所謂 "大道" 即支撐天地運轉的 "系統自動力"&#xff0c;更具體地來說&#xff0c;即是天地人以…