Html飛機大戰(九): 使徒來襲 (設計敵機)

来源:https://www.cnblogs.com/FatTiger4399/archive/2022/09/01/16644619.html
-Advertisement-
Play Games

好家伙,本篇介紹敵機 好了,按照慣例我們來理一下思路: 我們有一個敵機類,第一步當然是實例一個敵機對象, 然後我們把這個敵機放入我們的敵機群(敵機數組) 然後是熟悉的移動和繪製 那我們回顧一下子彈的生成邏輯 變數: 子彈 bullet 彈夾(用來裝子彈的東西)bulletList[] 方法:裝填子彈 ...


好家伙,本篇介紹敵機

 

好了,按照慣例我們來理一下思路:

 

我們有一個敵機類,第一步當然是實例一個敵機對象,

然後我們把這個敵機放入我們的敵機群(敵機數組)

然後是熟悉的移動和繪製

 

那我們回顧一下子彈的生成邏輯

變數: 子彈  bullet  彈夾(用來裝子彈的東西)bulletList[] 

方法:裝填子彈  繪製子彈 移動子彈

子彈發射的物理邏輯是很簡單的:

生產第一個子彈,推入彈夾中,繪製彈夾(即繪製彈夾中的所有子彈),

生產第二個子彈,同樣推入彈夾,移動第一顆子彈(應該說是改變第一顆子彈的y坐標),繪製彈夾中的所有子彈 

。。。。。。

生產第n個子彈,推入彈夾中,改變第n-1顆子彈的Y坐標,繪製彈夾中的所有子彈

 

有沒有感覺到兩者邏輯的相似之處

(像啊,太像了)

 

 

子彈和敵機的處理,本質上是用的是同一套邏輯

 

那麼,開始幹活:

 

1.配置項

這裡我們會用到兩種類型的配置項E1和E2

(因為我們有兩種類型的敵人,大敵機和小敵機,其中e1為小敵機(血少),e2為大敵機(血厚))

先設置一個數組存放圖片資源

//e1用於存放小敵機的圖片素材
        const e1 = {
            live: [],
            death: [],
        }
        e1.live[0] = new Image();
        e1.live[0].src = "img/enemy1.jpg"
        e1.death[0] = new Image();
        e1.death[0].src = "img/enemy1_boom1.jpg"
        e1.death[1] = new Image();
        e1.death[1].src = "img/enemy1_boom2.jpg"
        e1.death[2] = new Image();
        e1.death[2].src = "img/enemy1_boom3.jpg"

        //e2用於存放小敵機的圖片素材
        const e2 = {
            live: [],
            death: [],
        }
        e2.live[0] = new Image();
        e2.live[0].src = "img/enemy2.jpg"
        e2.death[0] = new Image();
        e2.death[0].src = "img/enemy2_boom1.jpg"

 

 

 

  

 

 

 

 (圖片素材來自網路)

 

 

 

 2.敵機配置項

//小敵機
        const E1 = {
            type: 1,
            width: 57,
            height: 51,
            life: 1, //少點血,一下打死
            score: 1,
            frame: e1,
            minSpeed: 20,
            maxSpeed: 10,
        }
        //大敵機
        const E2 = {
            type: 2,
            width: 69,
            height: 95,
            life: 2,
            frame: e2,
            minSpeed: 50,
            maxSpeed: 20,
        }
minSpeed: 50,
maxSpeed: 20,
值得說明一下,這兩個玩意是為了弄敵機的隨機速度(更刺激一點,但實際上好像沒什麼感覺)
關於如何弄到一個”隨機速度“,接著往下看


3.敵機類

class Enemy {

            constructor(config) {
                //敵機類型
                this.type = config.type;
                //敵機寬,高
                this.width = config.width;
                this.height = config.height;
                //敵機的初始化位置
                this.x = Math.floor(Math.random() * (480 - config.width));
                //這裡我們讓飛機從頭部開始渲染,所以Y軸坐標自然是飛機高度的負值
                this.y = -config.height;
                //敵機生命
                this.life = config.life;
                //敵機分數
                this.score = config.score;
                //敵機圖片庫
                this.frame = config.frame;
                //此刻展示的圖片
                this.img = null;
                //活著的證明
                this.live = true;
                // this.minSpeed = config.minSoeed;
                // this.maxSpeed = config.speed;
                //隨機去生成一個速度
                this.speed = Math.floor(Math.random() * (config.minSpeed - config.maxSpeed + 1)) + config.maxSpeed;
                //最後渲染的時間
                this.lastTime = new Date().getTime();

            }
            //移動敵機
            move() {
                const currentTime = new Date().getTime();
                //
                
                if (currentTime - this.lastTime >= this.speed) {
                    // console.log("此處為this.frame"+this.frame.live[0]);
                    this.img = this.frame.live[0];
                    this.y++;
                    //時間修正
                    this.lastTime = currentTime;
                }
            }

            //渲染敵機方法
            paint(context) {
                // console.log("此處為this.img"+this.img);
                if(this.img !=null){
                    context.drawImage(this.img, this.x, this.y);  
                }
                
            }
        }

 

 

3.1.隨機速度

先淺淺的說明一下

隨機數方法 Math.random

 

這玩意會在[0,1)也就是在0到1之間取一個值

然後問題來了,這是一個半開半閉區間,也就是說它會取到0但是不會取到1

this.speed = Math.floor(Math.random() * (config.minSpeed - config.maxSpeed + 1)) + config.maxSpeed;

在這裡我們要取的是一個10到20之間的速度由於我們向下取整

Math.floor(Math.random() * (config.minSpeed - config.maxSpeed )) + config.maxSpeed;

必然只能取得10-19之間的數


於是我們在(config.minSpeed - config.maxSpeed )中加一

變成(Math.random() * (config.minSpeed - config.maxSpeed +1))


(聰明的你一定能很快想明白,而愚蠢的我想了很久才想明白)


3.2.敵機的移動方法

move() {
                const currentTime = new Date().getTime();
                //
                
                if (currentTime - this.lastTime >= this.speed) {
                    // console.log("此處為this.frame"+this.frame.live[0]);
                    this.img = this.frame.live[0];
                    this.y++;
                    //時間修正
                    this.lastTime = currentTime;
                }
            }

移動同樣的用時間判定的方式去控制速率

現在和過去的時間差大於速度,更新地址


3.3.渲染方法

paint(context) {
                // console.log("此處為this.img"+this.img);
                if(this.img !=null){
                    context.drawImage(this.img, this.x, this.y);  
                }
                
            }

嗯,非常好理解了,多加的一個if是為了防止出現空img導致報錯


4.全局函數(生產敵機)

//以下三項均為全局變數
        const enemies = [];
        //敵機產生的速率
        const ENEMY_CREATE_INTERVAL = 2000;
        let ENEMY_LASTTIME = new Date().getTime();

        //全局函數 用於生產敵機
        function createComponent() {
            const currentTime = new Date().getTime();
            const forenemyTime = new Date().getTime();

            //一手經典判斷
            if (currentTime - ENEMY_LASTTIME >= ENEMY_CREATE_INTERVAL) {
                //當時間滿足 實例化一架敵機 放入敵機數組中
                // 小飛機 70% 中飛機30%
                //用隨機數去弄概率
                //[0,99]
                //Math.random()=>[0,1)*100
                //EnemyTypeRandom產生的隨機數用於判斷產生不同的飛機
                let EnemyTypeRandom = Math.floor(Math.random() * 100);
                if (EnemyTypeRandom > 70) {
                    enemies.push(new Enemy(E1));
                } else if (EnemyTypeRandom < 30) {
                    enemies.push(new Enemy(E2));
                }
                console.log(enemies);
                //更新時間
                ENEMY_LASTTIME = currentTime;
            }
        }

這裡同樣的,我們用隨機數去控制出現大/小敵機的概率

(E1,E2分別是大小敵機的配置項)



let EnemyTypeRandom = Math.floor(Math.random() * 100);
                if (EnemyTypeRandom > 70) {
            //產小敵機 enemies.push(new Enemy(E1)); }
else if (EnemyTypeRandom < 30) {
            //產大敵機 enemies.push(new Enemy(E2)); }

你細品,這個控制得還是非常巧妙的

 

5.全局函數渲染


到這裡就非常簡單了

這裡也揭開了前面的謎底

因為敵機生成和子彈生成的邏輯太過相似

所以我們把他們放到同一個全局函數是一個非常明智的選擇

//全局函數 來移動所有的子彈/敵人組件
        function judgeComponent() {
            console.log("judge被觸發");
            for (let i = 0; i < hero.bulletList.length; i++) {
                hero.bulletList[i].move();
            }
            for(let i=1;i<enemies.length;i++){
                enemies[i].move();
            }
        }
        //全局函數 來繪製所有的子彈/敵人組件
        function paintComponent() {
            for (let i = 0; i < hero.bulletList.length; i++) {
                hero.bulletList[i].paint(context);
            }
            for(let i=1;i<enemies.length;i++){
                enemies[i].paint(context);
            }
        }

 

6.方法調用



case RUNNING:
                        sky.judge();
                        sky.paint(context);
                        //載入主角

                        hero.paint(context);
                        hero.shoot();
                        createComponent();
                        //子彈發射
                        judgeComponent();
                        paintComponent();
                        deleteComponent();
                        // context.drawImage(hero_frame.live[0], 0, 0);
                        break;

 


 
ok,來看看效果吧:

 

 

 

確實是非常地nice啊

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 自從2020年底開始接觸 PostgreSQL 以來就喜歡上了這個資料庫,個人感覺比 MySQL 好用,多表聯合查詢性能好很多,同時也不存在 SQLServer 的版權授權費用問題。搭配 .NET 開發很好用,目前手裡的項目全部都是採用 PostgreSQL 進行數據支撐的。 本文主要說一下在 Wi ...
  • 近期,ArchSummit 全球架構師峰會(以下簡稱:AS峰會)北京站圓滿落幕。AS峰會是極客邦科技旗下 InfoQ 中國團隊推出的重點面向高端技術管理者、架構師的技術會議。AS峰會北京站以“升級架構思維,支撐業務發展”為目標,邀請各廠商展示先進技術在行業中的典型實踐,以及技術在企業轉型、發展中的推 ...
  • 1、您的應用程式必須使用正式的圖像。正式的文字,在上板時不要出現測試類圖像,例如一個母親嬰兒商店,你上傳了一個不相關的圖片。或者用測試字眼寫的圖像,都不能。文本中也不能出現測試類的單詞,如測試等。如果您以前在後臺上傳過測試字眼的產品,請先刪除它並重新登錄。 2、你的APP還沒有完成,如果模塊還沒有完 ...
  • 一、前言 AVCaptureSession 是 AVFoundation 的核心類,用於管理捕獲對象 AVCaptureInput 的視頻和音頻的輸入,協調捕獲的輸出 AVCaptureOutput。 AVCaptureOutput 的輸出有兩種方法: 一種是直接以 movieFileUrl 方式輸 ...
  • 用戶在瀏覽App的頁面時,如果經常跳出來不喜歡的彈窗廣告不僅損害用戶的瀏覽體驗,也讓用戶對廣告內容產生反感。作為App的營銷人員,線上投放廣告時如何精準捕捉用戶需求,同時不引起用戶的抵觸心理十分重要。當用戶不願意將自己的個人信息,例如年齡、性別、興趣愛好等隱私數據授權給App時,基於用戶正在瀏覽的頁 ...
  • 一、前言 動畫一直是 iOS 開發中很重要的一部分。設計良好,效果炫酷的動畫往往能對用戶體驗的提升起到很大的作用,在這裡將自己學習 iOS 動畫的體會記錄下來,希望能對別人有所幫助。 iOS 的動畫框架,即 CoreAnimation,本身十分龐大和複雜,這裡暫時分兩個部分進行介紹,分別是 UIVi ...
  • == 和 的區別 使用雙等號進行相等判斷時,如果兩邊的類型不一致,則會進行強制類型轉化後再進行比較; 使用三等號進行相等判斷時,如果兩邊的類型不一致時,不會做強制類型準換,直接返回 false; ==的判斷流程 首先判斷兩者類型是否相同,相同的話就比較兩者的大小;類型不相同的話,就會進行類型轉換。 ...
  • 年少不知Vue的好,錯把layui當成寶 不用太在意這句話,只是我的感慨 1.安裝與配置: 在HBuilderX創建Uniapp項目,可以不用啟動uniCloud,Vue的版本隨意選擇即可,常用vue2.x。 根據官方文檔的提示,安裝uview。 點擊紅框中的按鈕打開終端。 執行如下的命令: npm ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...