主頁 > 軟體設計 > js飛機大戰( ?° ?? ?°)

js飛機大戰( ?° ?? ?°)

2021-09-29 15:13:36 軟體設計

文章目錄

  • 一、游戲總體框架
      • 飛機大戰
      • 總體框架:
      • 運行方式
  • 二、游戲總體內容
    • 1.面向物件方案
    • 2.游戲主函式的入口Game.js
    • 3.這樣一來,我們就需要這樣一個檔案 proto.js
    • 4.上面配置都出來了,怎么可能游戲沒有背景呢 Background.js
    • 5.背景都有啦,咱們開始造玩家吧 Player.js
    • 6.來給我方飛機來個'皮膚' playerConfig.js
    • 7.咱也不可能打仗不帶槍啊 Bullet.js
    • 8.敵機來嘍 Enemy.js
    • 9.子彈爆裂圖片 Boom.js
    • 10.來看個分數吧 Score.js
    • 11.繼續努力吧(死亡重新開始嘍) 彈出層 DialogModal.js
    • 12.資料管理中心 不管是專案的尺寸還是碰撞,都在我這里哦Status.js
    • 13.飛機碰撞 tools.js
  • 三、說在后頭


一、游戲總體框架

飛機大戰

總體框架:

	    *       index.html                              入口界面
        *       static                                  專案的素材等內容
        *          |_ src                               代碼資源檔案夾
        *          |   |_ mod                           模塊檔案夾
        *          |   |   |_ Background.js             背景模塊
        *          |   |   |_ Player.js                 我方飛機
        *          |   |   |_ Boom.js                   爆炸圖片
        *          |   |   |_ Bullet.js                 子彈
        *          |   |   |_ DialogModal.js            彈出層(死亡后重新開啟游戲)
        *          |   |   |_ Enemy.js                  敵機
        *          |   |   |_ playerConfig.js           飛機配置事件
        *          |   |   |_ Score.js                  得分
        *          |   |_ lib                           封裝的庫
        *          |   |   |_ proto.js                  物件添加迭代器屬性,實作物件解構賦值
        *          |   |_ Game.js                       游戲主函式的入口
        *          |   |_ Status.js                     資料管理中心
        *          |   |_ tool.js                       計算矩形的公有面積是否碰撞
        *          |_ images                            圖片檔案夾

框架圖

運行方式

? 運行index.html檔案,然后按F12打開控制臺,切換至移動端,重繪頁面后,即可.

二、游戲總體內容

1.面向物件方案

本飛機大戰游戲,采用面向物件的方式,通過模塊化編程去撰寫…
同時,我們僅對外暴露出一個介面,一個Game的建構式
此為游戲的入口檔案 index.html

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>飛機大戰</title>
    <style>
        *{
            margin: 0;
        }
        html,body{
            width: 100%;
            height: 100%;
        }
    </style>
</head>
<body>
    <script type="module">
        import Game from "./static/src/Game.js";
        //初始化游戲
        //自動化做好所有事情 => 游戲初始化 (重啟游戲)
        //type="module" 所有代碼的作用域都是在script中,不會去全域內
        // let game = new Game(document.querySelector("body"))
        //于是用以下方法匯出到全域中
        window.game = new Game(document.querySelector("body"))
    </script>
</body>
</html>

2.游戲主函式的入口Game.js

代碼如下:

import "./lib/proto.js"
import status from "./Status.js";
import DialogModal from "./mod/DialogModal.js";
/*
* 游戲主函式的入口,用來初始化專案(canvas生成,事件的生成,專案尺寸資料的生成)
* */
class Game{
    constructor(container) {
        this.container = container
        //游戲的暫停狀態,沒有暫停的
        this.paused = false
        this.gameOver = false
        //系結this
        this.render = this.render.bind(this)
        this.pause = this.pause.bind(this)
        this.continue = this.continue.bind(this)
        //操控dom,初始化函式,當游戲實體化時,執行constructor,并走到init()中
        this.initCanvas()
        /*
            重啟游戲,包含第一次啟動
        */
        this.restartGame()
    }
    /*
    * 初始化canvas標簽,并設定尺寸,僅執行一次
    * */
    initCanvas(){
        this.canvas = document.createElement('canvas')
        this.canvas.style.display = 'block'
        this.canvas.width = this.container.getBoundingClientRect().width
        this.canvas.height = this.container.getBoundingClientRect().height
        this.ctx = this.canvas.getContext('2d')
        this.container.appendChild(this.canvas)
        this.restartDialog = new DialogModal(this.ctx)
        //狀態初始化
        status.init(this.canvas)

        this.container.onblur = this.pause
        this.container.onfocus = this.continue

        this.size = {
            w:status.size.w,
            h:status.size.h
        }

    }

    restartGame(){

        cancelAnimationFrame(this.frame)
        //我不希望重啟游戲的時候之前事件還是繼續生效的
        this.removeEvent()
        //注冊游戲基礎事件
        this.initEvent()
        status.reset()
        this.continue()
        this.render()
    }
    //馬不停蹄的去渲染,游戲的重繪頁面控制器
    render(){
        this.frame =  requestAnimationFrame(this.render)
        // console.log("render")
        // requestAnimationFrame(()=>{this.render()}) //也可以采用箭頭函式來實作

        if(this.paused) return
            //把筆跡擦干凈
            // this.ctx.clearRect(0,0,this.size.w,this.size.h)

            this.ctx.clearRect(0,0,...this.size)
            /*首先 更新資料*/
            status.update()
            // 背景是 渲染在最底層的所以最先寫
            status.render()
            // console.log(status.gameOver)
            if(status.gameOver){
                this.removeEvent()
                clearInterval(this.fireTimer)
                cancelAnimationFrame(this.frame)
                this.renderRestartRect()
                return
                // 跳轉到渲染別的內容
            }
    }
    // 渲染重新開始有的界面
    renderRestartRect(){
        this.restartDialog.render()
        this.restartDialog.bindEvent()
        this.restartDialog.handle(() => {
            this.restartGame()
        })
    }
    removeEvent(){
        //將這個player之前添加的事件移除
        status.player.removeEvent(this.canvas)
    }
    /*初始化事件系統*/
    initEvent(){
        window.onresize = e => {
            status.setSize(window.innerWidth, window.innerHeight)
        }
        // 作弊按鈕
        window.addEventListener("keydown", e => {
            if(e.key.toLowerCase() === "k"){
                status.enemyList.forEach( enemy => {
                    enemy.dead = true
                })
            }
        })
        status.player.initEvent(this.canvas)
    }

    //TODO 游戲暫停(事件系統會關閉)『全域』
    pause(){
        clearInterval(this.fireTimer)
        this.paused = true

    }
    //TODO 游戲繼續
    continue(){
        clearInterval(this.fireTimer)
        this.fireTimer = setInterval(status.fire.bind(status),1000/8)
        this.paused = false
    }
}
export default Game

看到this.ctx.clearRect(0,0,this.size.w,this.size.h)的時候,會不會覺得有點復雜,
那么我該怎樣使用一個可以去遍歷的物件屬性值,通過...

this.ctx.clearRect(0,0,...this.size) 

怎樣變成這樣呢?


3.這樣一來,我們就需要這樣一個檔案 proto.js

/*
    拓展一些原型的方法
    可以去遍歷的物件屬性值,我們用在...中
    ...解構物件

    @returns {IterableIterator<*>}
*/
Object.prototype[Symbol.iterator] = function* (){
    for (let i in this){
        yield this[i]
    }
}

Function.prototype.onceBind = (function (){
    //這里的閉包只有1個,我們的bindMap只有屬性名,屬性值兩個東西
    //針對于不同的函式,系結不同的內容
    const bindMap = new Map()
    return function (obj){
        //需要對obj和函式進行關聯 關聯兩個物件
        if(!bindMap.get(obj)){
            bindMap.set(obj,new Map())
        }
        //查詢obj里面的map函式對應關系,每個函式  對應著 => 那個函式相同的bind回傳的函式
        if(!bindMap.get(obj).get(this)){
            bindMap.get(obj).set(this,this.bind(obj))
        }
        return bindMap.get(obj).get(this)
    }
})();

/*
* 以上 onceBind:
*       用來相同函式bind相同物件的時候,回傳的函式與系結之后的函式是完全一致的
*
* 例如:
*   var obj = {};
*   var foo = function(){
*
*   }
*   var foo1 = foo.onceBind(obj)
*   var foo2 = foo.onceBind(obj)
*   foo1 == foo2
*   // true
*
*   函式 => 物件 => 唯一的系結結果
*
* */
/* 一:
*  1.fn1.onceBind(obj1) => bindFn11  生成,存盤,回傳  第一次執行
*  2.再次執行 fn1.onceBind(obj1) 如果obj1已經在bindMap中,那么我就回傳之前生成已存盤的值
*  二:
*  3.fn2.onceBind(obj1) => 最開始并沒找到,那我們就生成fn2 生成,存盤,回傳
*  三:
*  4:fn2.onceBind(obj2) => 最開始還是沒有 我們創建 bindFn22
*  四:
*  5:fn1.onceBind(obj2) => bindFn12
* */
//一
// let bindMap = {
//     obj1:{
//         fn1:"bindFn11"
//     }
// }
// //二
// let bindMap = {
//     obj1:{
//         fn1:"bindFn11",
//         fn2:"bindFn21"
//     }
// }
// //三
// let bindMap = {
//     obj1:{
//         fn1:"bindFn11",
//         fn2:"bindFn21"
//     },
//     obj2:{
//         fn2:"bindFn22"
//     }
// }
// //四
// let bindMap = {
//     obj1:{
//         fn1:"bindFn11",
//         fn2:"bindFn21"
//     },
//     obj2:{
//         fn2:"bindFn22",
//         fn1:"bindFn12"
//     }
// }

/*
* Map是es6的方法:類似于物件,但比物件還要強大,鍵值對都可以是物件
* */

4.上面配置都出來了,怎么可能游戲沒有背景呢 Background.js

import status from "../Status.js";
export default class Background {
    constructor(ctx) {
        this.ctx = ctx
        this.vy = 2
        //圖片的位置和大小

        this.rect1 = {
            x:0,
            y:0,
            ...status.size
        }
        this.rect2 = {
            x:0,
            y:this.rect1.y - status.size.h,
            ...status.size
        }
        this.init()
    }
    /*
        在加載的時候,準備好渲染的圖片以及自己的位置
    */
    init(){
        this.img = new Image()
        this.img.src = "static/images/bg.jpg"
    }
    reset(){
        this.rect1.y = 0
    }
    render(){
        // this.ctx.drawImage(this.img,0,0,status.size.w,status.size.h)
        // this.ctx.drawImage(this.img,0,0,...status.size)
        this.ctx.drawImage(this.img,...this.rect1)
        this.ctx.drawImage(this.img,...this.rect2)
    }
    update(){
        this.rect1.y += this.vy
        this.rect2.y = this.rect1.y - status.size.h
        //邊界判斷,瞬間歸0
        if(this.rect1.y >= status.size.h){
            this.rect1.y = 0
        }
    }
}

5.背景都有啦,咱們開始造玩家吧 Player.js

import status from "../Status.js";
import playerConfig from "./playerConfig.js";
import boomImgList from "./Boom.js";
export default class Player {
    constructor(ctx) {
        this.ctx = ctx
        //飛機是不可以拖拽的
        this.draged = false

        //角色的大小位置
        this.rect = {
            x:status.size.w / 2 - 49,
            y:status.size.h - 65,
            w:98,
            h:65
        }
        //是否處于爆炸
        this.booming = false
        this.boomingCount = 0
        this.vip = 1
        this.init()
        this.level = 1
    }
    init(){
        this.playerImg = new Image()
        this.img = this.playerImg
        this.img.src = "static/images/hero.png"
    }

    reset(){
        this.dead = false
        this.booming = false
        this.boomingCount = 0
        this.img = this.playerImg
        this.rect = {
            x:status.size.w / 2 - 49,
            y:status.size.h - 65,
            w:98,
            h:65
        }
    }

    render(){
        this.ctx.drawImage(this.img,...this.rect)
    }

    update(){
        //不允許飛機飛到螢屏外
        if(this.rect.x < 0){
            this.rect.x = 0
        }
        if(this.rect.x > status.size.w - this.rect.w){
            this.rect.x = status.size.w - this.rect.w
        }
        if(this.rect.y < 0){
            this.rect.y = 0
        }
        if(this.rect.y > status.size.h - this.rect.h){
            this.rect.y = status.size.h - this.rect.h
        }
        //如果處于boom的時候
        if(this.booming && this.boomingCount < boomImgList.length){
            this.img = boomImgList[this.boomingCount++]
        }
        if(this.boomingCount === boomImgList.length){
            this.dead = true
        }
    }
    //初始化當前飛機的事件
    initEvent(dom){
        //先說幾個互動任務
        //點是否在this.rect中 => 元素物件之間的互動(
        // 1.點和矩形是否重合 => 矩形和點是否有重合區域
        // 2.子彈和飛機互動 => 矩形和矩形是否有重合區域
        // 3.敵機和我方飛機的互動 => 矩形和矩形是否有重合區域
        // )
        // 函式bind方法每次都回傳的是一個全信的函式,自己封裝一個基于函式和系結主題的唯一的函式bind結果
        // console.log("注冊drag事件")
        playerConfig.forEach(item=>{
            item.handleList.forEach(fn =>{
                dom.addEventListener(item.type,fn.onceBind(this))
            })
        })
    }
    //移除之前注冊事件
    //我們的bind每一次都回傳新的函式,所以沒有辦法移除
    removeEvent(dom){
        playerConfig.forEach(item=>{
            item.handleList.forEach(fn =>{
                dom.removeEventListener(item.type,fn.onceBind(this))
            })
        })
    }
    kill(){
        this.booming = true
    }
}

6.來給我方飛機來個’皮膚’ playerConfig.js

import rectCollide from "../tools.js";

export default [
    {
        type: 'touchstart',
        handleList:[
            function(e){
                // console.log("touch")
                const mouseRect = {
                    x : e.changedTouches[0].clientX - 5,
                    y : e.changedTouches[0].clientY - 5,
                    w : 10,
                    h : 10
                }

                if(rectCollide(mouseRect,this.rect)){
                    this.draged = true
                }
            }
        ]
    },{
        type: 'touchmove',
        handleList:[
            function(e){
                if(!this.draged){
                    return
                }
                this.rect.x = e.changedTouches[0].clientX - this.rect.w /2
                this.rect.y = e.changedTouches[0].clientY - this.rect.h /2
            }
        ]
    },
    {
        type: 'touchend',
        handleList:[
            function(e){
                this.draged = false
            }
        ]
    }
]

7.咱也不可能打仗不帶槍啊 Bullet.js

//這里是子彈 咻咻咻~~
import status from "../Status.js";

export default class Bullet{
    constructor(ctx) {
        this.ctx = ctx
        this.dead = false
        this.rect = {
            x:0,
            y:0,
            w:18,
            h:27
        }
        this.vy = -3
        this.init()
    }
    setPosition(rect){
        this.rect.x = rect.x + (rect.w - this.rect.w)/2
        this.rect.y = rect.y - this.rect.h/2
    }
    init(){
        this.img = new Image()
        this.img.src = "static/images/bullet.png"
    }
    render(){
        this.ctx.drawImage(this.img,...this.rect)
    }
    update(){
        this.vy -= 0.1
        this.rect.y += this.vy
        //死亡判斷
        if(this.rect.y < - this.rect.h){
            this.kill()
        }
    }
    kill(){
        //殺死子彈
        this.dead = true
    }
}

8.敵機來嘍 Enemy.js

//敵機來嘍
import status from "../Status.js";
import boomImgList from "./Boom.js";

export default class Enemy{
    constructor(ctx) {
        this.ctx = ctx
        this.rect = {
            x:Math.random() * (status.size.w-60),
            y:-40,
            w:60,
            h:40
        }
        this.boomingCount = 0
        this.lives = 2
        //死了一半
        this.booming = false
        //死完了
        this.dead = false
        this.vy = Math.random() * 2 + 1
        this.init()
    }
    init(){
        this.img = new Image()
        this.img.src = "static/images/enemy.png"
    }
    render(){
        this.ctx.drawImage(this.img,...this.rect)
    }
    update(){
        //更新敵機事件
        this.rect.y += this.vy
        //飛到螢屏外面移除
        if(this.rect.y > status.size.h + this.rect.h){
            this.kill()
        }
        //如果是處于booming的狀態,那就修改this.img
        if(this.booming && this.boomingCount<boomImgList.length){
            this.img = boomImgList[this.boomingCount++]
        }
        if(this.boomingCount === boomImgList.length){
            this.dead = true
        }
    }
    kill(count = 1){
        this.lives -= count;
        if(this.lives <= 0){
            this.booming = true
            //殺死敵機了 殺死了
            // this.dead = true
        }

    }

}

9.子彈爆裂圖片 Boom.js

let length = 19
let boomImgList = []
for(let i = 0; i < length; i++){
    let img = new Image()
    img.src = `static/images/explosion${i+1}.png`
    boomImgList.push(img)
}
export default boomImgList

10.來看個分數吧 Score.js

import status from "../Status.js"

export default class Score {
  constructor(ctx){
    this.ctx = ctx
    this.ctx.font = "20px serif"
    this.ctx.fillStyle = "#ffffff"
    this.ctx.fontWeight = "bold"
    this.count = 0
  }
  add(){
    this.count ++
  }
  getMsg(){
    this.msg = `擊殺敵機${this.count}`
    return this.msg
  }
  reset(){
    this.count = 0
  }

  render(){
    // console.log(this.getMsg(), status.size.w - 50, 0, 50)
    this.ctx.beginPath()
    this.ctx.fillText(this.getMsg(), status.size.w - 100, 20, 100);
  }
}


11.繼續努力吧(死亡重新開始嘍) 彈出層 DialogModal.js

import Status from "../Status.js"
import rectCollide from "../tools.js"
export default class DialogModal {
  constructor(ctx){
    this.ctx = ctx
    this.rect = {
      x: Status.size.w / 4,
      y: Status.size.h / 4,
      w: Status.size.w / 2,
      h: Status.size.h / 2,
    }
    this.init()
  }

  init(){
    this.img = new Image()
    this.img.src = "static/images/restart.png"
  }

  render(){
    this.rect = {
      x: Status.size.w / 4,
      y: Status.size.h / 4,
      w: Status.size.w / 2,
      h: Status.size.w / 2,
    }
    this.ctx.drawImage(this.img, ...this.rect)
  }
  click (e) {
    let touchRect = {
      x: e.touches[0].clientX - 5,
      y: e.touches[0].clientY - 5,
      w: 10,
      h: 10
    }
    if(rectCollide(touchRect, this.rect)){
      this.removeEvent()
      this.fn()
    }
  }
  handle(fn){
    this.fn = fn
  }


  bindEvent(){
    Status.canvas.addEventListener("touchstart", this.click.onceBind(this))
  }
  removeEvent(){
    Status.canvas.removeEventListener("touchstart", this.click.onceBind(this))
  }
}


12.資料管理中心 不管是專案的尺寸還是碰撞,都在我這里哦Status.js

/*
    資料管理中心
    專案尺寸 飛機和子彈的碰撞,點擊位置和飛機的關系
    記錄全域狀態,可以在任何模塊里去引入,然后獲取全域的值
*/
import Background from "./mod/Background.js";
import Player from "./mod/Player.js";
import Bullet from "./mod/Bullet.js";
import Enemy from "./mod/Enemy.js";
import Score from "./mod/Score.js";
import rectCollide from "./tools.js";

class Status {
    constructor() {
        this.size = {
            w:0,
            h:0
        }
        this.gameOver = false
    }
    init(canvas){
        this.canvas = canvas
        this.ctx = this.canvas.getContext('2d')
        this.size.w = canvas.width
        this.size.h = canvas.height
        //初始化專案中的元素,包括背景,敵機等
        this.bg = new Background(this.ctx)
        this.player = new Player(this.ctx)
        this.score = new Score(this.ctx)
        //子彈串列
        this.bulletList = []
        //敵機串列
        this.enemyList = []
    }
    //發射子彈
    fire(){
        let bullet = null
        // 創建子彈并且渲染子彈 多個的
        switch (this.player.level) {
            case 1:
                bullet = new Bullet(this.ctx)
                bullet.setPosition(this.player.rect)
                this.bulletList.push(bullet)
                break
            case 2:
                bullet = new Bullet(this.ctx)
                let rect1 = {
                    x: this.player.rect.x - 10,
                    y: this.player.rect.y,
                    w: this.player.rect.w,
                    h: this.player.rect.h
                }
                bullet.setPosition(rect1)
                this.bulletList.push(bullet)

                bullet = new Bullet(this.ctx)
                let rect2 = {
                    x: this.player.rect.x + 10,
                    y: this.player.rect.y,
                    w: this.player.rect.w,
                    h: this.player.rect.h
                }
                bullet.setPosition(rect2)
                this.bulletList.push(bullet)
                break
        }
    }

    update(){
        this.bg.update()
        this.player.update()

        if(this.player.dead){
            this.gameOver = true
            return
        }


        this.bulletList.forEach( bullet => {
            bullet.update()
        })

        // 維護有效子彈
        this.bulletList = this.bulletList.filter( bullet => !bullet.dead)

        // 隨機生成敵機
        if(Math.random() < 0.06){
            this.enemyList.push(new Enemy(this.ctx))
        }

        this.enemyList.forEach( enemy => {
            enemy.update()
        })
        // 維護敵機的生死
        this.enemyList = this.enemyList.filter( enemy => !enemy.dead)
        if(this.score.count > 20){
            this.player.level = 2
        }
        // 碰撞檢測 子彈和 敵機的碰撞
        this.bulletList.forEach( bullet => {
            this.enemyList.forEach( enemy => {
                // 如果任何一架飛機和任何一發子彈有重合
                if(rectCollide(bullet.rect, enemy.rect)){
                    bullet.kill()
                    if(!enemy.booming){
                        enemy.kill(this.player.vip)
                        if(enemy.lives <= 0){
                            this.score.add()
                        }
                    }
                }
            })
        })

        // 我方飛機和敵機的碰撞

        this.enemyList.forEach( enemy => {
            if(rectCollide(enemy.rect, this.player.rect)  && !enemy.booming){
                enemy.kill(this.player.vip)
                this.player.kill()
            }
        })

    }
    render(){
        this.bg.render()
        this.player.render()
        // this.bullet.render()
        this.bulletList.forEach(bullet =>{
            bullet.render()
        })
        this.enemyList.forEach(enemy=>{
            enemy.render()
        })
        this.score.render()
    }
    reset(){
        this.gameOver = false
        this.bg.reset()
        this.player.reset()
        this.score.reset()
        this.bulletList = []
        this.enemyList = []
    }

    setSize(w, h){
        console.log("set")
        this.size.w = w
        this.size.h = h
    }

}

/*
    僅匯出一次,
    也就是說,不管在哪里匯入,都是相同的實體
*/
export default new Status()

13.飛機碰撞 tools.js

/*
* @param rectA :第一個矩形
* @param rectB :第二個矩形
* 計算這兩個矩形 是否有重合的地方
* @return Number 表示是否重合
* */

function rectCollide(rectA,rectB){
    //計算矩形的公有面積,如果面積大于0,那么就相交,否則就不相交

    //理論應該是左上位置的值
    //兩個矩形左上角x坐標中的最大值
    const xMin = Math.max(rectA.x,rectB.x)
    //兩個矩形左上角y坐標中的最大值
    const yMin = Math.max(rectA.y,rectB.y)

    //理論應該是右下位置的值
    //兩個矩形右下角x坐標中的最小值
    const xMax = Math.min(rectA.x + rectA.w,rectB.x + rectB.w)
    //兩個矩形右下角y坐標中的最小值
    const yMax = Math.min(rectA.y + rectA.h,rectB.y + rectB.h)
    //計算寬高
    const width = xMax - xMin
    const height = yMax - yMin
    //如果有面積,就可以回傳大于0的數,否則回傳0
    if(width > 0 && height > 0){
        return width * height
    }else{
        return 0
    }
}
export default rectCollide

三、說在后頭

在Player.js中 ,我寫了個this.vip = 1,大家能想到什么嘛 (??ヮ?) ? (?ヮ??),只有充錢才能變得強大. 在這里插入圖片描述
當然,身為一個作者,怎么能連自己的飛機都打不完呢?不不不,這樣絕對不可以.( ?° ?? ?°)于是偶在Game.js中,加入了作弊按鈕哦,畢竟你可以用瀏覽器打開嘛~

		window.addEventListener("keydown", e => {
            if(e.key.toLowerCase() === "k"){
                status.enemyList.forEach( enemy => {
                    enemy.dead = true
                })
            }
        })

( ?° ?? ?°) ( ?° ?? ?°) ( ?° ?? ?°) ( ?° ?? ?°)
完整版代碼呦~

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/304113.html

標籤:其他

上一篇:promise封裝uniapp中的uni.request

下一篇:Windows下Node.js安裝vue/cli以及創建簡單vue專案

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more