微信小游戏实战——飞机大战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"这样去填写图片路径


发布了208 篇原创文章 · 获赞 40 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/qq_42231156/article/details/104170835
今日推荐