微信小遊戲實戰——飛機大戰demo筆記完整篇(函數實現)

1. 目錄結構:

2. game.js:入口文件

//game.js文件完整代碼:
import Main from "./src/mian.js"
new Main()
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

 3. game.json:全家配置參數文件,參考https://developers.weixin.qq.com/minigame/dev/reference/configuration/app.html

{
  "deviceOrientation":"portrait",
  " showStatusBar":true
}

4. src/main.js:初始化js邏輯代碼文件:

import Background from "./all/background.js"
import Audio from "./all/audio.js"
import Hero from "./all/hero.js"
import Bullet from "./all/bullet.js"
import Enemy from "./all/enemy.js"
import Animation from "./all/animation.js"
import Text from "./all/text.js"

class main{
  constructor(){
    this.canvas = wx.createCanvas()
    this.ctx = this.canvas.getContext('2d')
    
    this.ch=GameGlobal.innerHeight //屏幕的高
    this.cw = GameGlobal.innerWidth //屏幕的寬

    this.bulletObjArr=[]  //存放屏幕內可見的子彈數組
    this.enemyObjArr=[]    //存放屏幕內可見的敵機數組
    this.animationObjArr=[]  //存放屏幕內可見的爆炸效果動畫的數組

    this.bangImgArr=[]  //提前緩存19張爆炸效果圖數組
    for(let i=0;i<19;i++){
      let obj={
        bang:wx.createImage()
      }
      obj.bang.src = `./images/explosion${i+1}.png`
      this.bangImgArr.push(obj)
    }

    this.scoreNum=0  //得分
    this.bgMoveTop=0  //背景圖片移動的上下位移
    this.initStart()   //初始化邏輯
  }
  initStart(){     
    let bgObj=new Background(this.ctx)  //實例化背景圖
    new Audio()   //實例化背景音樂
    let heroObj=new Hero(this.ctx)  //實例化英雄飛機

    let enemyObj = null
    var bulletObj = null

    setInterval(()=>{  //定時器,每隔300ms,繪製一個子彈 並存放在子彈數組中  
      bulletObj = new Bullet(this.ctx, heroObj)
      this.bulletObjArr.push(bulletObj)
    },300)
    setInterval(() => {  //定時器,每隔300ms,繪製一個敵機 並存放在敵機數組中 
       enemyObj = new Enemy(this.ctx)     
      this.enemyObjArr.push(enemyObj)
    },1000)

    let textObj = new Text(this.ctx)  //實例化得分和結束遊戲彈窗
    this.render(bgObj, heroObj, textObj)  //開始繪製,遞歸函數
  }
  render(bgObj, heroObj, textObj){
    this.bgMoveTop++
    this.bgMoveTop=this.bgMoveTop > this.ch ? 0 : this.bgMoveTop
    requestAnimationFrame(()=>{
      this.ctx.clearRect(0, 0, this.cw, this.ch)  //清空畫布
      bgObj.move(this.bgMoveTop)  //繪製背景
      
      this.bulletObjArr = this.bulletObjArr.filter(item=>item.isShow)  //過濾掉超出屏幕的子彈  
      this.bulletObjArr.forEach((item)=>{ //繪製連續的子彈
        item.draw()  //先繪製子彈再繪製飛機
      })

      textObj.scoreDraw(this.scoreNum)  //繪製分數
      heroObj.draw()  //繪製英雄飛機

      this.enemyObjArr = this.enemyObjArr.filter(item => item.isShow)  //過濾掉超出屏幕的子彈  
      this.enemyObjArr.forEach((item)=>{
        heroObj.isBang(item)  //檢測敵機和英雄飛機是否相撞
        item.draw()  //繪製敵機
        for (var i = 1; i < this.bulletObjArr.length;i++){
          let bool=item.isBang(this.bulletObjArr[i])       
          if(bool){  //擊中敵機
            this.scoreNum++
            this.bulletObjArr[i]=false
            let animate = new Animation(this.ctx, item.x, item.y)    //繪製爆炸效果
            this.animationObjArr.push(animate)
          }
          
        }
      })

      this.animationObjArr = this.animationObjArr.filter(item => item.isShow)  //繪製爆炸效果
      this.animationObjArr.forEach((item) => { //繪製爆炸效果
        item.draw(this.bangImgArr)  //繪製爆炸效果
      })
      if (!heroObj.isGameOver){  //遊戲結束,就停止繪製
        this.render(bgObj, heroObj, textObj)
      }else{  //遊戲結束 繪製結束時彈出
        textObj.popup(this.scoreNum)
      }
      
    })
  }


  
}


export default main

5. src/all/background.js:繪製背景圖

export default function(ctx){
  let width= GameGlobal.innerWidth,
    height= GameGlobal.innerHeight

  let obj={
    bg: wx.createImage(),
    width: width,
    height: height,
    move:function(top){ 
      ctx.drawImage(this.bg, 0, 0, this.bg.width,this.bg.height, 0, top ,this.width,this.height)
      ctx.drawImage(this.bg, 0, 0, this.bg.width, this.bg.height, 0, top - this.height, this.width, this.height)
    }
  }
  obj.bg.src='images/bg.jpg'
  obj.bg.width=512
  obj.bg.height=512

  return obj
}

6. src/all/hero.js:繪製英雄飛機


export default function (ctx) {
  let  width = GameGlobal.innerWidth,
    height = GameGlobal.innerHeight
  let obj = {
    newHero: wx.createImage(),
    x:0,
    y:0,
    imgW:80,
    imgH:80,
    isGameOver:false,  //遊戲是否結束,即結束時停止渲染畫圖
    draw: function () {
      ctx.drawImage(this.newHero, 0, 0, this.newHero.width, this.newHero.height, this.x, this.y, this.imgW, this.imgH)  
    },
    isBang:function(enemy){
      let cX=enemy.x+enemy.imgW/2 
      let cY = enemy.y + enemy.imgH / 2
      if(cX>this.x && cX<this.x+this.imgW && cY>this.y && cY<this.y+this.imgH){
        // console.log("飛機和影響飛機相撞了,game over")
        this.isGameOver=true
      }
    }
  }
  obj.newHero.src = 'images/hero.png'
  obj.newHero.width = 186
  obj.newHero.height = 130
  obj.x = width / 2 - obj.imgW/2
  obj.y = height - obj.imgH -30


  let isMove = false
  wx.onTouchStart((e) => {
    let touch = e.changedTouches[0]  //獲取手指按下的對象
    let touX = touch.clientX
    let touY = touch.clientY
   
    if (touX > obj.x && touX < obj.x + obj.newHero.width / 2 && touY > obj.y && touY < obj.y + obj.newHero.height / 2) {
      isMove = true
    }
  })
  wx.onTouchMove((e) => {
    let touch = e.changedTouches[0]  //獲取手指按下的對象
    let touX = touch.clientX
    let touY = touch.clientY
    if (isMove) {
      let x = touX - obj.imgW / 2
      let y = touY - obj.imgH / 2

      x=x<0?0:x  //限制飛機可以拖拽的邊界範圍
      x = x > width - obj.imgW ? width - obj.imgW:x
      
      y=y<0?0:y
      y = y > height - obj.imgH ? height - obj.imgH : y

      obj.x = x
      obj.y = y
    }
  })
  wx.onTouchEnd((e) => {
    isMove = false
  })

  return obj
}

7. src/all/bullet.js:繪製子彈

export default function (ctx, heroObj){
  let width = GameGlobal.innerWidth,
    height = GameGlobal.innerHeight
  let obj={
    newBullet: wx.createImage(),
    x: 0,
    y: 0,
    imgW: 16,
    isShow:true,  //是否超出屏幕顯示
    imgH: 30,
    draw: function () {
      this.y-=5
      if (this.y< -30){  //判斷子彈是否飛出屏幕
        this.isShow=false
      }
      ctx.drawImage(this.newBullet, 0, 0, this.newBullet.width, this.newBullet.height, this.x, this.y, this.imgW, this.imgH)
    }
  }
  obj.newBullet.src = 'images/bullet.png'
  obj.newBullet.width = 62
  obj.newBullet.height = 108
  obj.x = heroObj.x + heroObj.imgW / 2 - obj.imgW/2
  obj.y = heroObj.y+10

  let biu = wx.createInnerAudioContext()  //發射子彈的聲音
  biu.src="audios/bullet.mp3"
  biu.play()

  return obj
}

8. src/all/enemy.js:繪製敵機

export default function(ctx){
  let width = GameGlobal.innerWidth,
    height = GameGlobal.innerHeight
  let obj={
    enemy: wx.createImage(),
    x:0,
    y:-60,
    imgW:60,
    imgH:60,
    isShow:true,  //當敵機溢出屏幕時,隱藏
    draw:function(){
      this.y = this.y+5
      if (this.y > height + this.imgH){
        this.isShow = false
      }
      ctx.drawImage(this.enemy, 0, 0, this.enemy.width, this.enemy.height,this.x,this.y,this.imgW,this.imgH)     
    },
    isBang:function(bullet){  //敵機是否與子彈碰撞到
      var cX = bullet.x + bullet.imgW/2
      var cY = bullet.y + bullet.imgH / 2
      if (cX > this.x && cX<this.x+this.imgW && cY>this.y && cY<this.y+this.imgH && this.y>30){  
        // console.log("子彈在屏幕內打中敵機了")
        this.isShow=false
        return true
      }
    }
  }
  obj.enemy.src ="images/enemy.png"
  obj.enemy.width=120
  obj.enemy.height=79
  
  obj.x=Math.random()*(width-obj.imgW)
  return obj
}

9. src/all/animation.js:繪製爆炸效果

export default function(ctx,dx,dy){
  let  width = GameGlobal.innerWidth,
    height = GameGlobal.innerHeight
  let obj={
    num:0,
    isShow:true,
    draw: function (bangImgArr){
      this.num++
      if(this.num>18){
        this.num=18
        this.isShow=false
      }
      ctx.drawImage(bangImgArr[this.num].bang,0,0,64,48,dx,dy,60,60)
    }
  }

  // let boom = wx.createInnerAudioContext()  //爆炸聲音
  // boom.src = "audios/boom.mp3"
  // boom.play()

  return obj
}

 10. src/all/text.js:繪製得分以及遊戲結束彈窗

export default function(ctx){
  let width = GameGlobal.innerWidth,
    height = GameGlobal.innerHeight
  let obj={
    img:wx.createImage(),
    btnImg:wx.createImage(),
    scoreDraw:function(score){  //繪製分數
      ctx.font='20px arial'
      ctx.fillStyle='#fff'
      ctx.fillText(score,10,40)
    },
    popup: function (score){  //分別是繪製背景彈出和重新開始的按鈕背景圖
      ctx.drawImage(this.img,0,0,119,108,width/2-150,height/2-100,300,300)
      ctx.fillText('遊戲結束', width/2-40, height/2-100+50)
      ctx.fillText(`得分:${score}`, width / 2 - 40, height / 2 - 100+130)
      ctx.drawImage(this.img, 120, 6, 39, 24, width / 2 - 60, height / 2 - 100+180, 120, 40) 
      ctx.fillText('重新開始', width / 2 - 40, height / 2 - 100+205)
    }
  }
  obj.img.src ="images/Common.png"
  return obj
}

 11. src/all/audio.js:繪製背景音樂

class audio {
  constructor() {
    this.newAudio = wx.createInnerAudioContext()
    this.newAudio.src='audios/bgm.mp3'
    this.newAudio.play()
  }
}

export default audio

備註:

1. 創建game.json全局配置:參考https://developers.weixin.qq.com/minigame/dev/reference/configuration/app.html。
  全局配置參數:
    1.1 deviceOrientation:屏幕選擇方向,包括豎屏('portrait')和橫屏('landscape')。
    1.2 showStatusBar:是否顯示手機頂部電量,信號燈狀態欄,默認爲false,只有在豎屏下才能顯示狀態欄。
    
2. wx.drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh):作爲參數。dx和dy是image在canvas中定位的座標值;dw和dh是image在canvas中即將繪製區域(相對dx和dy座標的偏移量)的寬度和高度值;sx和sy是image所要繪製的起始位置,sw和sh是image所要繪製區域(相對image的sx和sy座標的偏移量)的寬度和高度值。

3. img.src="./images/xxx.png"的圖片路徑,在真機上顯示不出來,需要img.src="images/xxx.png"這樣去填寫圖片路徑


 

 

 

 

 

 

 

 

 

 

 

發佈了209 篇原創文章 · 獲贊 40 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章