最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Vue3+Canvas實(shí)現(xiàn)坦克大戰(zhàn)游戲(二)

 更新時(shí)間:2022年03月18日 10:00:40   作者:Ethan_Zhou  
本文主要給大家講解一下子彈擊中物體、物體銷(xiāo)毀、敵方坦克構(gòu)建生成、運(yùn)動(dòng)算法、爆炸效果、以及障礙物的生成,感興趣的小伙伴可以了解一下

前言

接著上篇講,本篇主要給大家講解一下子彈擊中物體、物體銷(xiāo)毀、敵方坦克構(gòu)建生成、運(yùn)動(dòng)算法、爆炸效果、以及障礙物的生成;了解了這些我相信你可以不依賴游戲引擎實(shí)現(xiàn)大部分小游戲的開(kāi)發(fā)。

Es5版本: 在線游戲 源代碼

W/上 S/下 A/左 D/右 F/射擊

讓我們開(kāi)始吧!

敵方坦克的生成

我們可以使用 for 循環(huán)和Tank 構(gòu)造函數(shù),批量制造多個(gè)敵方坦克,x,y 為其在畫(huà)布中的坐標(biāo),direction 為坦克當(dāng)前方向,type 為精靈圖中截取坦克圖片的信息,包含了坐標(biāo),尺寸,類(lèi)型等

for(let t=0; t<20; t++) {
  let tank = new Tank(new TankConfig({
    x: 100 + t*30,
    y: 100,
    direction: DIRECTION.DOWN,
    type: TANK_TYPE.ENEMY0,
    is_player: 0
  }))
  tank.star();
}

ENEMY0: {
  type: 'ENEMY1',
  dimension: [30, 30],
  image_coordinates: [129, 1, 129, 33]
}

坦克移動(dòng)的算法

emove 函數(shù)就是就是物體移動(dòng)狀態(tài)下每幀都會(huì)執(zhí)行的函數(shù),將根據(jù)當(dāng)前方向修改下幀的坐標(biāo),當(dāng)下幀坐標(biāo)到達(dá)地圖邊緣時(shí)將執(zhí)行 dir 函數(shù)更新坦克方向,如果是子彈則將銷(xiāo)毀。

this.emove = function (d, obstacle_sprites) {
    this.direction = d
    switch (d) {
      case DIRECTION.UP:
        if (
          (obstacle_sprites && !this.checkRangeOverlap(obstacle_sprites)) ||
          !obstacle_sprites
        ) {
          this.y -= this.speed
    
          if (this.y <= 10) {
            this.dir()
          }
        } else {
          this.dir()
        }
        break
    ...

dir 函數(shù)用來(lái)隨機(jī)修改移動(dòng)的方向,當(dāng)然這個(gè)函數(shù)不能每幀都調(diào)用,否則坦克將像無(wú)頭蒼蠅一樣了;那么什么時(shí)候需要修改方向呢,我們認(rèn)為當(dāng)坦克和物體相撞的時(shí)候或者到達(dá)地圖邊緣時(shí)修改方向是合理的;子彈也可以認(rèn)為是一個(gè)物體,所以子彈到達(dá)坦克周邊一定距離時(shí)也將引起坦克規(guī)避動(dòng)作,也就是將觸發(fā)dir 函數(shù)。

this.dir = function () {
    if(Math.floor(Math.random()*10) === 0 || Math.floor(Math.random()*10) === 1) {
      this.direction = DIRECTION.UP;
    };
    if(Math.floor(Math.random()*10) === 2 || Math.floor(Math.random()*10) === 3) {
      this.direction = DIRECTION.DOWN;
    };
    if(Math.floor(Math.random()*10) === 4 || Math.floor(Math.random()*10) === 5) {
      this.direction = DIRECTION.LEFT;
    };
    if(Math.floor(Math.random()*10) === 6 || Math.floor(Math.random()*10) === 7) {
      this.direction = DIRECTION.RIGHT;
    };
    if(Math.floor(Math.random()*10) === 8 || Math.floor(Math.random()*10) === 9) {
      this.dir();
    }
}

子彈擊中物體的算法

我們定義 checkRangeOverlap 函數(shù)來(lái)判斷兩個(gè)物體是否相撞,uiobjs 為畫(huà)布中所有的元素對(duì)象列表,包含 坦克、子彈、障礙物等;

this.getFrontPoints() 函數(shù)將根據(jù)當(dāng)前方向返回包含三個(gè)頂端點(diǎn)坐標(biāo)數(shù)組,形成判斷區(qū)域;

uiobjs[o].getCornerPoints() 函數(shù)返回當(dāng)前元素的四個(gè)邊角坐標(biāo)數(shù)組,形成判斷區(qū)域;

然后getFrontPoints() 的三個(gè)點(diǎn)坐標(biāo) 將分別和 uiobjs[o].getCornerPoints() 的四邊坐標(biāo)進(jìn)行點(diǎn)對(duì)點(diǎn)判斷,根據(jù)x, y 數(shù)值滿足下方四個(gè)條件時(shí)則認(rèn)為此點(diǎn)坐標(biāo)在元素內(nèi)部。

 // 判斷點(diǎn)坐標(biāo)是否在區(qū)域內(nèi)部,以識(shí)別是否相撞
  CanvasSprite.prototype.checkRangeOverlap = function (uiobjs) {
    for (let o in uiobjs) {
      let obstacle_cp = uiobjs[o].getCornerPoints()
      let fp = this.getFrontPoints()

      for (let idx = 0; idx < fp.length; idx++) {
        if (
          fp[idx].x > obstacle_cp[0].x &&
          fp[idx].x < obstacle_cp[1].x &&
          fp[idx].y > obstacle_cp[0].y &&
          fp[idx].y < obstacle_cp[2].y
        ) {
          return true
        }
      }
    }
    return false
  }
// 返回當(dāng)前物體頂端三坐標(biāo)
  CanvasSprite.prototype.getFrontPoints = function () {
    let front_point
    switch (this.direction) {
      case DIRECTION.UP:
        front_point = [
          new Point(this.x, this.y),
          new Point((2 * this.x + this.width) / 2, this.y),
          new Point(this.x + this.width, this.y),
        ]
        break
      ... 縮略,下左右方向
    }
    return front_point
  }
// 返回元素四邊坐標(biāo)形成的矩形區(qū)域范圍
  CanvasSprite.prototype.getCornerPoints = function () {
    var corner_points
    switch (this.direction) {
      case DIRECTION.UP:
        corner_points = [
          new Point(this.x, this.y),
          new Point(this.x + this.width, this.y),
          new Point(this.x + this.width, this.y + this.height),
          new Point(this.x, this.y + this.height),
        ]
        break
        ... 縮略,下左右方向
    }
    return corner_points
  }

啊 坦克搞多了!但是可以看到子彈擊中效果是成功的,你發(fā)現(xiàn)了沒(méi),擊中后有一個(gè)爆炸效果,這個(gè)是怎么實(shí)現(xiàn)的呢?

爆炸效果的實(shí)現(xiàn)

當(dāng)識(shí)別到擊中后將此坦克將觸發(fā)explode 爆炸效果,然后每幀 判斷 isDestroied 是否銷(xiāo)毀,后續(xù)每幀將 explosion_count++ 從 0 到 5,然后更改alive 狀態(tài)為0 代表已銷(xiāo)毀。

if (s instanceof Tank && s.alive && s.isDestroied()) {
    s.explode()
}
this.isDestroied = function () {
    return explosion_count > 0
  }
  
this.explode = function () {
    if (explosion_count++ === 5) {
      this.alive = 0
    }
  }

然后 explosion_count 的數(shù)值,從0 到 5 代表爆炸效果圖的5幀

  this.getImg = function () {
    if (explosion_count > 0) {
      return {
        width: TANK_EXPLOSION_FRAME[explosion_count].dimension[0],
        height: TANK_EXPLOSION_FRAME[explosion_count].dimension[1],
        offset_x: TANK_EXPLOSION_FRAME[explosion_count].image_coordinates[0],
        offset_y: TANK_EXPLOSION_FRAME[explosion_count].image_coordinates[1],
      }
    } else {
      return {
        width: width,
        height: height,
        offset_x: this.type.image_coordinates[0],
        offset_y: this.type.image_coordinates[1],
      }
    }
  }

到現(xiàn)在我們的坦克游戲已經(jīng)基本可玩了,只不過(guò)現(xiàn)在是一片大平原,毫無(wú)遮攔,我們?cè)摓楫?huà)布增加一些障礙物如墻體,石頭等,增加游戲可玩性。

生成障礙物(石墻、磚墻等)

有了之前tanke 和 子彈的構(gòu)建函數(shù),現(xiàn)在這個(gè) Block 就簡(jiǎn)單多了,只需要定義好基本的信息,如坐標(biāo),寬高、狀態(tài)、方向,然后借用 apply 來(lái)使用 CanvasSprite 上的通用方法。

    let Block = function (x, y, direction, type) {
      type = type || BLOCK_TYPE.BLOCK_BRICK
      let alive = 1
      let width = type.dimension[0]
      let height = type.dimension[1]
      let explosion_count = 0
      this.type = type

      this.x = x
      this.y = y
      this.genre = 'block'
      this.direction = direction || DIRECTION.UP

      CanvasSprite.apply(this, [
        {
          alive: 1,
          border_y: HEIGHT,
          border_x: WIDTH,
          speed: 0,
          direction: direction,
          x: x,
          y: y,
          width: width,
          height: height,
        },
      ])

      this.isDestroied = function () {
        return explosion_count > 0
      }

      this.explode = function () {
        if (explosion_count++ === 5) {
          this.alive = 0
        }
      }

      this.getImg = function () {
        if (explosion_count > 0) {
          return {
            width: TANK_EXPLOSION_FRAME[explosion_count].dimension[0],
            height: TANK_EXPLOSION_FRAME[explosion_count].dimension[1],
            offset_x: TANK_EXPLOSION_FRAME[explosion_count].image_coordinates[0],
            offset_y: TANK_EXPLOSION_FRAME[explosion_count].image_coordinates[1],
          }
        } else {
          return {
            width: width,
            height: height,
            offset_x: type.image_coordinates[0],
            offset_y: type.image_coordinates[1],
          }
        }
      }

      this._generateId = function () {
        return uuidv4()
      }

      sprites[this._generateId()] = this
    }

定義好后,使用時(shí)只需批量生成Block 的實(shí)例,將坐標(biāo),類(lèi)型等信息傳遞進(jìn)去就可以在下一幀渲染出來(lái)。

  for(let i=0; i<=2; i++) {
    for(let j=0; j<=2; j++) {
      let block = new Block(j*16, 140 + i*16, DIRECTION.UP, BLOCK_TYPE.BLOCK_STONE)
    }
  }

好了我們看看最終的效果吧!

總結(jié)

ok 坦克大戰(zhàn)基本上完成了,你可以修改子彈發(fā)射速度,敵方坦克數(shù)量,障礙物也可以自己隨意畫(huà),可玩性還是挺好的,當(dāng)然還有很多細(xì)節(jié)可以完善,如 預(yù)制幾種不同的地圖,做成通關(guān)類(lèi),預(yù)制幾條生命等。如果你想試一下,可以 star 下 github 倉(cāng)庫(kù)自己來(lái)改造自己的坦克大戰(zhàn)吧。

以上就是Vue3+Canvas實(shí)現(xiàn)坦克大戰(zhàn)游戲(二)的詳細(xì)內(nèi)容,更多關(guān)于Vue3 Canvas坦克大戰(zhàn)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • vue中字典的使用

    vue中字典的使用

    這篇文章主要介紹了vue中字典的使用,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2023-12-12
  • vue DatePicker日期選擇器時(shí)差8小時(shí)問(wèn)題

    vue DatePicker日期選擇器時(shí)差8小時(shí)問(wèn)題

    這篇文章主要介紹了vue DatePicker日期選擇器時(shí)差8小時(shí)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • vue 項(xiàng)目常用加載器及配置詳解

    vue 項(xiàng)目常用加載器及配置詳解

    本文介紹了vue 項(xiàng)目常用加載器及配置詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-01-01
  • Vue下拉菜單組件化開(kāi)發(fā)詳解

    Vue下拉菜單組件化開(kāi)發(fā)詳解

    這篇文章主要為大家詳細(xì)介紹了Vue下拉菜單組件化開(kāi)發(fā)過(guò)程,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • Vue分頁(yè)查詢?cè)趺磳?shí)現(xiàn)

    Vue分頁(yè)查詢?cè)趺磳?shí)現(xiàn)

    這篇文章主要介紹了Vue分頁(yè)查詢?cè)趺磳?shí)現(xiàn),使用vue實(shí)現(xiàn)分頁(yè)的邏輯并不復(fù)雜,接收后端傳輸過(guò)來(lái)的數(shù)據(jù),然后根據(jù)數(shù)據(jù)的總數(shù)和每一頁(yè)的數(shù)據(jù)量就可以計(jì)算出一共可以分成幾頁(yè)
    2023-04-04
  • vue elementUI table表格數(shù)據(jù) 滾動(dòng)懶加載的實(shí)現(xiàn)方法

    vue elementUI table表格數(shù)據(jù) 滾動(dòng)懶加載的實(shí)現(xiàn)方法

    這篇文章主要介紹了vue elementUI table表格數(shù)據(jù)滾動(dòng)懶加載的實(shí)現(xiàn)方法,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-04-04
  • vue?3.0?vue.config.js文件常用配置方式

    vue?3.0?vue.config.js文件常用配置方式

    這篇文章主要介紹了vue?3.0?vue.config.js文件常用配置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • Vue之插槽的內(nèi)容渲染問(wèn)題及解決過(guò)程

    Vue之插槽的內(nèi)容渲染問(wèn)題及解決過(guò)程

    本文將探討這些常見(jiàn)問(wèn)題的原因,并提供相應(yīng)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-03-03
  • vue2?web多標(biāo)簽輸入框elinput是否當(dāng)前焦點(diǎn)詳解

    vue2?web多標(biāo)簽輸入框elinput是否當(dāng)前焦點(diǎn)詳解

    這篇文章主要介紹了vue2?web多標(biāo)簽輸入框elinput是否當(dāng)前焦點(diǎn)的相關(guān)資料,講解了如何在產(chǎn)品中實(shí)現(xiàn)用戶輸入文字后按下回車(chē)鍵生成標(biāo)簽并顯示在頁(yè)面上的功能,通過(guò)組件的使用和改造,解決了輸入不連續(xù)的問(wèn)題,需要的朋友可以參考下
    2025-01-01
  • Vue中實(shí)現(xiàn)深度監(jiān)聽(tīng)的方法小結(jié)

    Vue中實(shí)現(xiàn)深度監(jiān)聽(tīng)的方法小結(jié)

    在Vue中,深度監(jiān)聽(tīng)是一種非常常見(jiàn)且重要的功能,它可以讓我們監(jiān)聽(tīng)對(duì)象內(nèi)部的所有屬性,并對(duì)這些屬性的變化做出相應(yīng)的處理,在本篇博客中,我將為大家介紹Vue中如何實(shí)現(xiàn)深度監(jiān)聽(tīng)的方法,需要的朋友可以參考下
    2024-09-09

最新評(píng)論

宜章县| 民乐县| 沐川县| 介休市| 新密市| 娱乐| 博罗县| 泗阳县| 徐闻县| 阿巴嘎旗| 汉沽区| 乡宁县| 阳高县| 周口市| 靖远县| 台中县| 宁安市| 乌兰察布市| 额济纳旗| 绍兴市| 灵川县| 车险| 沈阳市| 囊谦县| 沿河| 靖宇县| 繁峙县| 凌源市| 合阳县| 高唐县| 新密市| 秦皇岛市| 那曲县| 广河县| 盐池县| 莱芜市| 鹰潭市| 蓝田县| 集贤县| 阿勒泰市| 鄢陵县|